澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站快速构建爬虫,爬取动态网

2019-05-18 作者:www.8455.com   |   浏览(150)

澳门新萄京官方网站 1

       准备爬取太平洋网上的小米手机的评论,因为发现评论已经自动打好标签了,并且对于手机的几种性能表现也打了分,以及详细的评论都有,对于后面自己的工作有帮助,所以就准备爬取这些评论.但发现这个网站的每次点下一页都是相同的URL地址,也就是说源代码只显示第一页的评论内容,对于用requests来爬取网页内容,用这个地址的话无法爬取更多内容。后来查了一下,这是用了Ajax动态加载技术,专门用来动态加载网页内容,实现网页的异步更新。

说实话,我很想把文章标题写成“如何利用网络请求抢票抢优惠券”


《纽约时报》2012年2月的一篇专栏中所称,“大数据”时代已经降临,在商业、经济及其他领域中,决策将日益基于数据和分析而作出,而并非基于经验和直觉。随大数据时代一起来来临的,是越来越多的大数据工作岗位。在此,我们利用Python编程,抓取智联招聘、51job等网站上面有关大数据的工作岗位数据。

作者:叶耀荣
源自:

     关于Ajax的比较详细的解释推荐两个链接,比较详细的阐述了这是怎么回事,爬取Ajax动态加载和翻页时url不变的网页 网站案例,爬取Ajax动态加载和翻页时url不变的网页。自己说一下我遇到的问题,以及如何既解决的方法,我的问题比较简单就是翻页url地址不变,无法爬取下一页评论的内容。其实这是因为网站的网站隐藏住了url地址后面的参数部分,只显示了地址的主体部分,办法很简单就是找到这些网页url地址被隐藏的参数部分。下面讲一下我的解决步骤:

为了能让大家搞清楚原理,首先让我们简单地从流程上分析,点击一次“购买”按钮到底发生了什么。

序言
第1章 Scrapy介绍
第2章 理解HTML和XPath
第3章 爬虫基础
第4章 从Scrapy到移动应用
第5章 快速构建爬虫
第6章 Scrapinghub部署
第7章 配置和管理
第8章 Scrapy编程
第9章 使用Pipeline
第10章 理解Scrapy的性能
第11章(完) Scrapyd分布式抓取和实时分析

爬虫基础知识

不知道有没有小哥哥、小姐姐喜欢cosplay的,今天小编就分享一个关于爬取cosplay图片,emmmm,先来几张图活跃一下气氛!

      我爬去的网站是这个小米6x(4GB RAM)点评,当你点开网站点击下一页,再看看对应的url地址都是一样的没有变化,再看看对应的源代码发现都是一样的,只显示第一页的评论内容,第2,3,4....内容无法找到。开始找网站被隐藏的url参数部分。我用的浏览器时谷歌Chrome浏览器,按F12打开开发者选项,打开找到最上面导航栏network,下面选择All,筛选网页文件类型,这里也可选XHR表示动态网页类型,选择右边的preview来展示网页的内容用来确定我们要找的网页,

  1. 购买之前,网页肯定是会让你登录的对吧,当你登录之后呢,其实会生成一个Cookie保存在浏览器,用于校验你的身份。需要注意的是,这个Cookies不同的网站会有不同的有效时间,过期之后会提示你重新登录。

  2. 当我们鼠标点击“购买”按钮后,其实是在执行JavaScript代码。此时会生成一些参数,表示你的身份,比如你要购买的物品id,物品数量,当前时间等等,然后将这些参数使用一定的规则拼接起来,形成了FormData,它记录了你想做的操作

    当然,并不是所有的操作都是通过FormData来实现的,有的请求会采用Query String Parameters的形势,主要特点是将请求内容拼接在URL后面,如

  3. 于是,有了这两个必须的参数后,就能向服务器发起网络请求了,请求的目标网址Request URL,这个网址可以通过抓包获取,或者自己分析js代码。在header里设置上我们的Cookie表明身份,通过目标网址向服务器发送我们的请求内容FormData(或使用QueryStringParameters)。这样的一个网络请求,就是点击“购买”按钮真正起作用的步骤。


数据来源

网络爬虫的数据一般都来自服务器的响应结果,通常有html和json数据等,这两种数据也是网络爬虫的主要数据来源。
其中html数据是网页的源代码,通过浏览器-查看源代码可以直接查看,例如:

澳门新萄京官方网站 2

简书主页部分源码示例

json是一种数据存储格式,往往包含了最原始的数据内容,一般不直接显示在网页中,这里我们可以通过Chrome浏览器-开发者工具中的Network选项捕获到服务器返回的json数据,例如:

澳门新萄京官方网站 3

简书首页json数据示例

澳门新萄京官方网站 4

澳门新萄京官方网站 5

至于如何发起这样的网络请求,在网页上点击自然是使用了网站提供的JavaScript代码。而我们如果想要模拟这样一个操作,可以用不同语言的代码去实现。

第3章中,我们学习了如何从网页提取信息并存储到Items中。大多数情况都可以用这一章的知识处理。本章,我们要进一步学习抓取流程UR2IM中两个R,Request和Response。

数据请求

数据请求的方式一般有两种:GET方法和POST方法。我们也可以通过Chrome浏览器来捕获我们访问一个浏览器时的所有请求。这里以简书主页为例,打开Chrome浏览器开发者工具(F12),切换到Network选项,在地址栏输入http://www.jianshu.com/, 选择XHR类型,可以看到一条请求的内容,打开Headers,在General中可以看到请求方式为GET方式,
其中的Request Headers便是我们访问这个网页时的请求数据,如下图。

澳门新萄京官方网站 6

Request Headers

这个Headers可以用Python中的字典来表示,包含了用户请求的一些信息,例如编码、语言、用户登陆信息、浏览器信息等。
下面还有一个Query String Parameters,这里面包含了用户请求的一些参数,也是请求数据的一部分。

  • 利用requests库请求数据
    利用Python构建数据请求的方式有很多,在python3中,主要有urllib和requests两个类库可以实现该功能。urllib是官方标准库,其官方文档传送门。这里我们主要介绍第三方库requests,它是基于urllib编写的,比urllib用起来更加便捷,可以节约时间。
    澳门新萄京官方网站,requests安装方法:
$  pip install requests

利用requests构建数据请求主要方式:

import requests
req = request.get(url)

或者

import requests
req = requests.post(url)

其中,get()与post()中都可以添加headers、params等参数,以字典的形式传递即可。一般来说,简单的网页通过传入url数据即可成功请求数据。不过一些网站采用了反爬虫机制,需要我们传入headers及params等参数,以模拟浏览器访问、用户登陆等行为,才可以正常请求数据。

  • 利用webdriver请求数据
    webdriver是一个用来进行复杂重复的web自动化测试的工具,能够使用chrome、firefox、IE浏览器进行web测试,可以模拟用户点击链接,填写表单,点击按钮等。因此,相对于requests库来说,webdriver在模拟浏览器鼠标点击滑动等事件上有着天然的优势,并且真实模拟了浏览器的操作,不易被反爬虫机制发现,因此是一个很好用的爬虫工具。当然,其缺点在于速度较慢,效率不高。
    webdriver安装:
$ pip install selnium

除了安装selnium库,webdriver的运行还需要进行浏览器驱动的配置。Chrome、火狐和IE浏览器都有其配置方式,具体方法查看链接http://blog.163.com/yang_jianli/blog/static/1619900062014102833427464/。
这里我们以IE浏览器为例,做一个简单的示范:

from selenium import webdriver
import os
iedriver = "IEDriverServer.exe"
os.environ["webdriver.ie.driver"] = iedriver
driver = webdriver.Ie(iedriver)

如此,IE浏览器配置完毕,其中"IEDriverServer.exe"是IE浏览器驱动的存储路径。
于是,我们我们访问简书网主页数据只一步:

driver.get(http://www.jianshu.com/)

 

我们点击最左侧网页中的下一页就会在边上的对应文件中找到这个网页的代码文件信息,通过preview可以看见这个文件的预览。当我们找到要找的网页时,在点击headers找到我们所要的信息。

我对java代码熟悉一点,用java编写了一个小软件提供给那些不会代码或者懒癌玩家使用,同时提供了定时,秒杀等等功能。GitHub地址:NetRobot

一个具有登录功能的爬虫

你常常需要从具有登录机制的网站抓取数据。多数时候,网站要你提供用户名和密码才能登录。我们的例子,你可以在http://web:9312/dynamic或http://localhost:9312/dynamic找到。用用户名“user”、密码“pass”登录之后,你会进入一个有三条房产链接的网页。现在的问题是,如何用Scrapy登录?

澳门新萄京官方网站 7

让我们使用谷歌Chrome浏览器的开发者工具搞清楚登录的机制。首先,选择Network标签(1)。然后,填入用户名和密码,点击Login(2)。如果用户名和密码是正确的,你会进入下一页。如果是错误的,会看到一个错误页。

一旦你点击了Login,在开发者工具的Network标签栏中,你就会看到一个发往http://localhost:9312/dynamic/login的请求Request Method: POST。

提示:上一章的GET请求,通常用来获取静止数据,例如简单的网页和图片。POST请求通常用来获取的数据,取决于我们发给服务器的数据,例如这个例子中的用户名和密码。

点击这个POST请求,你就可以看到发给服务器的数据,其中包括表单信息,表单信息中有你刚才输入的用户名和密码。所有数据都以文本的形式发给服务器。Chrome开发者工具将它们整理好并展示出来。服务器的响应是302 FOUND(5),然后将我们重定向到新页面:/dynamic/gated。只有登录成功时才会出现此页面。如果没有正确输入用户名和密码就前往http://localhost:9312/dynamic/gated,服务器会发现你作弊,并将你重定向到错误页面:http://localhost:9312/dynamic/error。服务器怎么知道你和密码呢?如果你点击左侧的gated(6),你会发现在RequestHeaders(7)下有一个Cookie(8)。

提示:HTTP cookie是通常是一些服务器发送到浏览器的短文本或数字片段。反过来,在每一个后续请求中,浏览器把它发送回服务器,以确定你、用户和期限。这让你可以执行复杂的需要服务器端状态信息的操作,如你购物车中的商品或你的用户名和密码。

总结一下,单单一个操作,如登录,可能涉及多个服务器往返操作,包括POST请求和HTTP重定向。Scrapy处理大多数这些操作是自动的,我们需要编写的代码很简单。
我们将第3章名为easy的爬虫重命名为login,并修改里面名字的属性,如下:

class LoginSpider(CrawlSpider):
    name = 'login'

提示:本章的代码github的ch05目录中。这个例子位于ch05/properties。

我们要在http://localhost:9312/dynamic/login上面模拟一个POST请求登录。我们用Scrapy中的类FormRequest来做。这个类和第3章中的Request很像,但有一个额外的formdata,用来传递参数。要使用这个类,首先必须要引入:

from scrapy.http import FormRequest

我们然后将start_URL替换为start_requests()方法。这么做是因为在本例中,比起URL,我们要做一些自定义的工作。更具体地,用下面的函数,我们创建并返回一个FormRequest:

# Start with a login request
def start_requests(self):
  return [
    FormRequest(
      "http://web:9312/dynamic/login",
      formdata={"user": "user", "pass": "pass"}
         )]

就是这样。CrawlSpider的默认parse()方法,即LoginSpider的基本类,负责处理响应,并如第3章中使用Rules和LinkExtractors。其余的代码很少,因为Scrapy负责了cookies,当我们登录时,Scrapy将cookies传递给后续请求,与浏览器的方式相同。还是用scrapy crawl运行:

$ scrapy crawl login 
INFO: Scrapy 1.0.3 started (bot: properties)
...
DEBUG: Redirecting (302) to <GET .../gated> from <POST .../login >
DEBUG: Crawled (200) <GET .../data.php>
DEBUG: Crawled (200) <GET .../property_000001.html> (referer: .../data.
php)
DEBUG: Scraped from <200 .../property_000001.html>
  {'address': [u'Plaistow, London'],
   'date': [datetime.datetime(2015, 11, 25, 12, 7, 27, 120119)],
   'description': [u'features'],
   'image_URL': [u'http://web:9312i02.jpg'],
...
INFO: Closing spider (finished)
INFO: Dumping Scrapy stats:
  {...
   'downloader/request_method_count/GET': 4,
   'downloader/request_method_count/POST': 1,
...
   'item_scraped_count': 3,

我们注意到登录跳转从dynamic/login到dynamic/gated,然后就可以像之前一样抓取项目。在统计中,我们看到一个POST请求和四个GET请求;一个是dynamic/gated首页,三个是房产网页。

提示:在本例中,我们不保护房产页,而是是这些网页的链接。代码在相反的情况下也是相同的。

如果我们使用了错误的用户名和密码,我们将重定向到一个没有URL的页面,进程并将在这里结束,如下所示:

$ scrapy crawl login
INFO: Scrapy 1.0.3 started (bot: properties)
...
DEBUG: Redirecting (302) to <GET .../dynamic/error > from <POST .../
dynamic/login>
DEBUG: Crawled (200) <GET .../dynamic/error>
...
INFO: Spider closed (closespider_itemcount)

这是一个简单的登录示例,演示了基本的登录机制。大多数网站可能有更复杂的机制,但Scrapy也处理的很好。例如一些网站在执行POST请求时,需要通过从表单页面到登录页面传递某种形式的变量以确定cookies的启用,让你使用大量用户名和密码暴力破解时变得困难。

澳门新萄京官方网站 8

例如,如果你访问http://localhost:9312/dynamic/nonce,你会看到一个和之前一样的网页,但如果你使用Chrome开发者工具,你会发现这个页面的表单有一个叫做nonce的隐藏字段。当你提交表单http://localhost:9312/dynamic/nonce-login时,你必须既要提供正确的用户名密码,还要提交正确的浏览器发给你的nonce值。因为这个值是随机且只能使用一次,你很难猜到。这意味着,如果要成功登陆,必须要进行两次请求。你必须访问表单、登录页,然后传递数值。和以前一样,Scrapy有内建的功能可以解决这个问题。

我们创建一个和之前相似的NonceLoginSpider爬虫。现在,在start_requests()中,我们要向表单页返回一个简单的Request,并通过设定callback为名字是parse_welcome()的方法手动处理响应。在parse_welcome()中,我们使用FormRequest对象中的from_response()方法创建FormRequest,并将原始表单中的字段和值导入FormRequest。FormRequest.from_response()可以模拟提交表单。

提示:花时间看from_response()的文档是十分值得的。他有许多有用的功能如formname和formnumber,它可以帮助你当页面有多个表单时,选择特定的表单。

它最大的功能是,一字不差地包含了表单中所有的隐藏字段。我们只需使用formdata参数,填入user和pass字段,并返回FormRequest。代码如下:

# Start on the welcome page
def start_requests(self):
    return [
        Request(
            "http://web:9312/dynamic/nonce",
            callback=self.parse_welcome)
    ]
# Post welcome page's first form with the given user/pass
def parse_welcome(self, response):
    return FormRequest.from_response(
        response,
        formdata={"user": "user", "pass": "pass"}
    )

像之前一样运行爬虫:

$ scrapy crawl noncelogin 
INFO: Scrapy 1.0.3 started (bot: properties)
...
DEBUG: Crawled (200) <GET .../dynamic/nonce>
DEBUG: Redirecting (302) to <GET .../dynamic/gated > from <POST .../
dynamic/login-nonce>
DEBUG: Crawled (200) <GET .../dynamic/gated>
...
INFO: Dumping Scrapy stats:
  {...
   'downloader/request_method_count/GET': 5,
   'downloader/request_method_count/POST': 1,
...
   'item_scraped_count': 3,

我们看到第一个GET请求先到/dynamic/nonce,然后POST,重定向到/dynamic/nonce-login之后,之后像之前一样,访问了/dynamic/gated。登录过程结束。这个例子的登录含有两步。只要有足够的耐心,无论多少步的登录过程,都可以完成。

数据解析

使用requests请求下来的数据,可以利用.text()方法或者.content()方法访问,对于文本请求,二者并无太大差别,主要在于编码问题。具体用法可以参考官方文档,这里不再赘述。使用webdriver请求下来的数据可以用.page_source属性获取。请求下来的数据一般包含了大量的网页源代码,如何将其解析以提取出我们想要的内容呢?

  • html类型数据解析
    html语言即超文本标记语言,它是由一个个html标签构成的,是结构化的语言,因此很容易从中匹配提取信息。这种类型的数据解析的方法有很多,比如利用正则表达式,按照html标签的结构进行字符串匹配,或则利用lxml库中的xpath方法使用xpath路径定位到每一个节点、也有类似jQuery的PyQuery方法。这里我们主要介绍BeautifulSoup方法。
    Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间。该介绍来源于其官方中文文档,传送门。利用BeautifulSoup我们能够将html字符串转化为树状结构,并非常快速地定位到每一个标签。
    目前版本是BeautifulSoup4,pip安装方法:
$ pip install BeautifulSoup4

或者,下载bs4的源码,然后解压并运行:

$ python setup.py install 

利用BeautifulSoup解析html数据的关键步骤为:

from bs4 import BeautifulSoup
soup = BeautifulSoup(req.contents, "html.parser")

如果采用webdriver请求数据,那么则是:

from bs4 import BeautifulSoup
soup = BeautifulSoup(driver.page_source, "html.parser")

如此,便将html数据转换成BeautifulSoup中的树状结构。然后利用BeautifulSoup中的find()、find_all()等方法即可定位到每一个节点。详情请参阅官方文档。

  • json类型数据解析
    json类型的数据已经是高度结构化的数据,跟Python中字典的表示形式一样,因此在解析上十分方便。我们可以通过:
import json
data = json.loads(req.text)

直接读取json数据,且能够返回字典类型。

澳门新萄京官方网站 9

澳门新萄京官方网站 10

举一个bilibili投硬币的例子,这个例子是比较常见的POST请求。看一下当我们想要给喜欢的视频投硬币,到底是怎么进行的网络请求。

使用JSON APIs和AJAX页面的爬虫

有时,你会发现网页的HTML找不到数据。例如,在http://localhost:9312/static/页面上右键点击检查元素(1,2),你就可以在DOM树种看到所有HTML元素。或者,如果你使用scrapy shell或在Chrome中右键点击查看网页源代码(3,4),你会看到这个网页的HTML代码不包含任何和值有关的信息。数据都是从何而来呢?

澳门新萄京官方网站 11

和以前一样,在开发者工具中打开Network标签(5)查看发生了什么。左侧列表中,可以看到所有的请求。在这个简单的页面中,只有三个请求:static/我们已经检查过了,jquery.min.js是一个流行的JavaScript框架,api.json看起来不同。如果我们点击它(6),然后在右侧点击Preview标签(7),我们可以看到它包含我们要找的信息。事实上,http://localhost:9312/properties/api.json包含IDs和名字(8),如下所示:

[{
    "id": 0,
    "title": "better set unique family well"
}, 
... {
    "id": 29,
    "title": "better portered mile"
}]

这是一个很简单的JSON API例子。更复杂的APIs可能要求你登录,使用POST请求,或返回某种数据结结构。任何时候,JSON都是最容易解析的格式,因为不需要XPath表达式就可以提取信息。

Python提供了一个强大的JSON解析库。当我们import json时,我们可以使用json.loads(response.body)解析JSON,并转换成等价的Python对象,语句、列表和字典。

复制第3章中的manual.py文件。这是最好的方法,因为我们要根据JSON对象中的IDs手动创建URL和Request。将这个文件重命名为api.py,重命名类为ApiSpider、名字是api。新的start_URL变成:

start_URL = (
    'http://web:9312/properties/api.json',
)

如果你要做POST请求或更复杂的操作,你可以使用start_requests()方法和前面几章介绍的方法。这里,Scrapy会打开这个URL并使用Response作为参数调用parse()方法。我们可以import json,使用下面的代码解析JSON:

def parse(self, response):
    base_url = "http://web:9312/properties/"
    js = json.loads(response.body)
    for item in js:
        id = item["id"]
        url = base_url   "property_d.html" % id
        yield Request(url, callback=self.parse_item)

这段代码使用了json.loads(response.body)将响应JSON对象转换为Python列表,然后重复这个过程。对于列表中的每个项,我们设置一个URL,它包含:base_url,property_d和.html.base_url,.html.base_url前面定义过的URL前缀。d是一个非常有用的Python词,可以让我们结合多个Python变量形成一个新的字符串。在本例中,用id变量替换d。id被当做数字(%d的意思就是当做数字进行处理),并扩展成6个字符,位数不够时前面添加0。如果id的值是5,d会被替换为000005;id是34322时,d会被替换为034322替换。最后的结果是可用的URL。和第3章中的yield一样,我们用URL做一个新的Request请求。运行爬虫:

$ scrapy crawl api
INFO: Scrapy 1.0.3 started (bot: properties)
...
DEBUG: Crawled (200) <GET ...properties/api.json>
DEBUG: Crawled (200) <GET .../property_000029.html>
...
INFO: Closing spider (finished)
INFO: Dumping Scrapy stats:
...
   'downloader/request_count': 31, ...
   'item_scraped_count': 30,

最后一共有31次请求,每个项目一次,api.json一次。

大数据职位数据爬虫实战

这里我们以51job网站为例,构建大数据相关职位的数据爬虫。其中搜索关键词为:

数据科学家
数据分析师
数据架构师
数据工程师
统计学家
数据库管理员
业务数据分析师
数据产品经理
  • 网页分析
    打开51job首页http://www.51job.com/, 在搜索框中输入“数据科学家”,将搜索框中的地区点开,去掉当前勾选的城市,即默认在全国范围搜索。点击“搜索”按钮,得到搜索结果。这时我们将网址栏URL复制出来:
 http://search.51job.com/list/000000,000000,0000,00,9,99,
%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6%E5%AE%B6,
2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99
&jobterm=99&companysize=99&providesalary=99&lonlat=0,0&radius=-1&ord_field=0
&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=

结果不止一页,点击第二页,同样将URL复制出来:

http://search.51job.com/list/000000,000000,0000,00,9,99,
%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6%E5%AE%B6,
2,2.html?lang=c&stype=1&postchannel=0000&workyear=99&cotype=99&degreefrom=99
&jobterm=99&companysize=99&lonlat=0,0&radius=-1&ord_field=0
&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=

很容易发现,这两段url唯一的不同在于".html"前面的数字1和2,因此它代表了页码。其中:

%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6%E5%AE%B6

是一种URL编码,翻译成中文就是“数据科学家”,转换方式可以使用urllib库中的quote()方法:

import urllib.quote
keyword = '数据科学家'
url = quote(keyword)

我们可以通过第一次的搜索结果获取页码数:

def GetPages(keyword):
    keyword = quote(keyword, safe='/:?=')
    url = 'http://search.51job.com/jobsearch/search_result.php?fromJs=1&jobarea=000000,00&district=000000&funtype=0000&industrytype=00&issuedate=9&providesalary=99&keyword=' keyword   
      '&keywordtype=2&curr_page=1&lang=c&stype=1&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&lonlat=0,0&radius=-1&ord_field=0&list_type=0&fromType=14&dibiaoid=0&confirmdate=9'
    html = requests.get(url)
    soup = BeautifulSoup(html.content, "html.parser")
    span = soup.find('div', class_='p_in').find('span', class_='td')
    page_num = span.get_text().replace('共', '').replace('页,到第', '')
    return page_num

由此,便可实现针对特定关键词的所有搜索结果的页面的遍历。

  • URL列表构建
    打开搜索结果页面,我们会发现,点击职位名称可以链接到每个职位的详情页面,也正是我们所需要的数据源。因此,我们只需要获取所有的搜索结果中的职位名称的超链接地址,便可以遍历所有职位的详细数据:
def GetUrls(keyword, page_num):
    keyword = quote(keyword, safe='/:?=')
    urls = []
    p = page_num 1
    for i in range(1, p):
        url = 'http://search.51job.com/jobsearch/search_result.php?fromJs=1&jobarea=000000,00&district=000000&funtype=0000&industrytype=00&issuedate=9&providesalary=99&keyword=' keyword   
            '&keywordtype=2&curr_page='   
            str(i)   
            '&lang=c&stype=1&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&lonlat=0,0&radius=-1&ord_field=0&list_type=0&dibiaoid=0&confirmdate=9'
        html = requests.get(url)
        soup = BeautifulSoup(html.content, "html.parser")
        ps = soup.find_all('p', class_='t1')
        for p in ps:
            a = p.find('a')
            urls.append(str(a['href']))
        s = random.randint(5, 30)
        print(str(i) 'page done,' str(s) 's later')
        time.sleep(s)
    return urls
  • 数据请求构建
    在获取了所有的职位数据的url之后,我们使用requests访问这些url发现,并不能顺利获取数据。因此,可以考虑在请求中加入headers数据,其中包含cookie和User_Agent:
User_Agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
cookie = 'guid=14842945278988500031; slife=indexguide=1'
headers = {'User-Agent': User_Agent, 'cookie': cookie}

这样,可以成功请求每个职位的详情页面数据:

  • 数据解析
    数据解析首先是明确数据需求,这里我们将数据尽可能多的抓取下来。
    以职位要求一栏为例,我们通过访问多个页面对比发现,这一栏可能显示的要求个数不一样:

澳门新萄京官方网站 12

这里包括了经验、学历、招聘人数和发布时间

澳门新萄京官方网站 13

而这里则没有对于经验的要求。
利用浏览器开发者选项功能,查看这一栏的源码:

澳门新萄京官方网站 14

这里职位的要求都放在一个class="sp4"的span中,通过查找功能可以发现没有其他的class="sp4"的标签,所以我们利用find_all()方法可以轻松定位到这些职位要求数据。

通过比较可以发现这最多的要求个数为4,所以在个数不确定的情况下,可以先新建一个包含四个空字符串元素的新数组,将所有的要求个数填入该数组,这样可以保证不同网页的数据都能获取完整。

spans = soup.find_all('span', class_='sp4')
num = len(spans)
nav = ['', '', '', '']
for i in range(0, num-1):
    nav[i] = spans[i].get_text().strip()

完整代码如下:

# -*- coding: utf-8 -*-
from urllib.parse import quote
import requests
from bs4 import BeautifulSoup
import time
import random


def GetPages(keyword):
    keyword = quote(keyword, safe='/:?=')
    url = 'http://search.51job.com/jobsearch/search_result.php?fromJs=1&jobarea=000000,00&district=000000&funtype=0000&industrytype=00&issuedate=9&providesalary=99&keyword=' keyword   
        '&keywordtype=2&curr_page=1&lang=c&stype=1&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&lonlat=0,0&radius=-1&ord_field=0&list_type=0&fromType=14&dibiaoid=0&confirmdate=9'
    html = requests.get(url)
    soup = BeautifulSoup(html.content, "html.parser")
    span = soup.find('div', class_='p_in').find('span', class_='td')
    page_num = span.get_text().replace('共', '').replace('页,到第', '')
    return page_num


def GetUrls(keyword, page_num):
    keyword = quote(keyword, safe='/:?=')
    urls = []
    p = page_num 1
    for i in range(1, p):
        url = 'http://search.51job.com/jobsearch/search_result.php?fromJs=1&jobarea=000000,00&district=000000&funtype=0000&industrytype=00&issuedate=9&providesalary=99&keyword=' keyword   
            '&keywordtype=2&curr_page='   
            str(i)   
            '&lang=c&stype=1&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&lonlat=0,0&radius=-1&ord_field=0&list_type=0&dibiaoid=0&confirmdate=9'
        html = requests.get(url)
        soup = BeautifulSoup(html.content, "html.parser")
        ps = soup.find_all('p', class_='t1')
        for p in ps:
            a = p.find('a')
            urls.append(str(a['href']))
        s = random.randint(5, 30)
        print(str(i) 'page done,' str(s) 's later')
        time.sleep(s)
    return urls


def GetContent(url, headers):
    html = requests.get(url, headers=headers)
    soup = BeautifulSoup(html.content, "html.parser")
    PositionTitle = str(soup.find('h1')['title'])
    Location = soup.find('span', class_='lname').string
    Salary = soup.find('strong').string
    CompanyName = soup.find('p', class_='cname').get_text().strip()
    CompanyType = soup.find(
        'p', class_='msg ltype').get_text().strip().replace(' ', '').replace('  ', '').replace('  ', '').replace('  ', '')
    spans = soup.find_all('span', class_='sp4')
    num = len(spans)
    nav = ['', '', '', '']
    for i in range(0, num-1):
        nav[i] = spans[i].get_text().strip()
    Exp = nav[0]
    Degree = nav[1]
    RecruitNum = nav[2]
    PostTime = nav[3]
    Welfare = soup.find('p', class_='t2')
    if str(type(Welfare)) == "<class 'NoneType'>":
        Welfare = ''
    else:
        Welfare = Welfare.get_text().strip().replace('n', '|')
    PositionInfo = soup.find(
        'div', class_='bmsg job_msg inbox').get_text().strip().replace('n', '').replace('分享', '').replace('举报', '').replace('  ', '').replace(' ', '').replace('   ', '').replace('    ', '').replace('r', '')
    PositionType = soup.find('span', class_='el')
    if str(type(PositionType)) == "<class 'NoneType'>":
        PositionType = ''
    else:
        PositionType = PositionType.get_text().strip().replace('n', '')
    Contact = soup.find('div', class_='bmsg inbox')
    if str(type(Contact)) == "<class 'NoneType'>":
        Contact = ''
    else:
        Contact = Contact.get_text().strip().replace(
            '   ', '').replace('    ', '').replace('地图', '').replace('n', '')
    ConpanyInfo = soup.find('div', class_='tmsg inbox')
    if str(type(ConpanyInfo)) == "<class 'NoneType'>":
        ConpanyInfo = ''
    else:
        ConpanyInfo = ConpanyInfo.get_text().strip().replace(
            'n', '').replace('  ', '').replace(' ', '')
    try:
        record = PositionTitle 't' Location 't' Salary 't' CompanyName 't' CompanyType 't' Exp 't' Degree 't'   
            RecruitNum 't' PostTime 't' Welfare 't' PositionInfo   
            't' str(PositionType) 't' str(Contact) 't' str(ConpanyInfo)
    except Exception as e:
        record = ''
    else:
        pass
    finally:
        pass
    return record


def main():
    with open('keywords.txt', 'r', encoding='utf-8') as f:
        keywords = f.readlines()
    for keyword in keywords[1:]:
        keyword = keyword.strip()
        page_num = int(GetPages(keyword))
        urls = GetUrls(keyword, page_num)
        with open(keyword 'urls.txt', 'w', encoding='utf-8') as f:
            for url in urls:
                f.write(url 'n')
        User_Agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
        cookie = 'guid=14842945278988500031; slife=indexguide=1'
        headers = {'User-Agent': User_Agent, 'cookie': cookie}
        with open(keyword 'urls.txt', 'r', encoding='utf-8') as f:
            urls = f.readlines()
        records = []
        i = 0
        for url in urls:
            url = url.strip()
            if url != '':
                records.append(
                    GetContent(url, headers))
                i  = 1
                s = random.randint(5, 30)
                print(str(i) 'page done,' str(s) 's later')
                time.sleep(s)
        with open(keyword '.txt', 'w', encoding='utf-8') as f:
            for re in records:
                f.write(re 'n')
        print(keyword ' Done---------------------------')


if __name__ == '__main__':
    main()

 

 

现在我想要给新番刀剑神域投硬币,于是我点击了投币,这一瞬间发生了什么。

在响应间传递参数

许多时候,你想把JSON APIs中的信息存储到Item中。为了演示,在我们的例子中,对于一个项,JSON API在返回它的名字时,在前面加上“better”。例如,如果一个项的名字时“Covent Garden”,API会返回“Better Covent Garden”。我们要在Items中保存这些含有“bette”的名字。如何将数据从parse()传递到parse_item()中呢?

我们要做的就是在parse()方法产生的Request中进行设置。然后,我们可以从parse_item()的的Response中取回。Request有一个名为meta的字典,在Response中可以直接访问。对于我们的例子,给字典设一个title值以存储从JSON对象的返回值:

title = item["title"]
yield Request(url, meta={"title": title},callback=self.parse_item)

在parse_item()中,我们可以使用这个值,而不用XPath表达式:

l.add_value('title', response.meta['title'],
      MapCompose(unicode.strip, unicode.title))

你会注意到,我们从调用add_xpath()切换到add_value(),因为对于这个字段不需要使用XPath。我们现在运行爬虫,就可以在PropertyItems中看到api.json中的标题了。

澳门新萄京官方网站 15

Query String Parameters显示了我们请求的网页地址的参数部分,也就是我们网页的主体部分是' ' String Parameters.

我们可以使用浏览器自带的抓包工具,以Chrome浏览器为例,点击浏览器的检查按钮,找到Network,点击clear清楚掉之前的请求记录,如下图

一个加速30倍的项目爬虫

当你学习使用一个框架时,这个框架越复杂,你用它做任何事都会很复杂。可能你觉得Scrapy也是这样。当你就要为XPath和其他方法变得抓狂时,不妨停下来思考一下:我现在抓取网页的方法是最简单的吗?

如果你可以从索引页中提取相同的信息,就可以避免抓取每一个列表页,这样就可以节省大量的工作。

提示:许多网站的索引页提供的项目数量是不同的。例如,一个网站可以通过调整一个参数,例如&show=50,给每个索引页面设置10、 50或100个列表项。如果是这样的话,将其设置为可用的最大值。

例如,对于我们的例子,我们需要的所有信息都存在于索引页中,包括标题、描述、价格和图片。这意味着我们抓取单个索引页,提取30个条目和下一个索引页的链接。通过抓取100个索引页,我们得到3000个项,但只有100个请求而不是3000个。

在真实的Gumtree网站上,索引页的描述比列表页的完整描述要短。这是可行的,或者是更推荐的。

提示:许多情况下,您不得不在数据质量与请求数量间进行折衷。很多网站都限制请求数量(后面章节详解),所以减少请求可能解决另一个棘手的问题。

在我们的例子中,如果我们查看一个索引页的HTML,我们会发现,每个列表页有自己的节点,itemtype="http://schema.org/Product"。节点有每个项的全部信息,如下所示:

澳门新萄京官方网站 16

让我们在Scrapy shell中加载索引首页,并用XPath处理:

$ scrapy shell http://web:9312/properties/index_00000.html
While within the Scrapy shell, let's try to select everything with the Product tag:
>>> p=response.xpath('//*[@itemtype="http://schema.org/Product"]')
>>> len(p)
30
>>> p
[<Selector xpath='//*[@itemtype="http://schema.org/Product"]' data=u'<li 
class="listing-maxi" itemscopeitemt'...]

我们得到了一个包含30个Selector对象的表,每个都指向一个列表。Selector对象和Response对象很像,我们可以用XPath表达式从它们指向的对象中提取信息。不同的是,表达式为有相关性的XPath表达式。相关性XPath表达式与我们之前见过的很像,不同之处是它们前面有一个点“.”。然我们看看如何用.//*[@itemprop="name"][1]/text()提取标题的:

>>> selector = p[3]
>>> selector
<Selector xpath='//*[@itemtype="http://schema.org/Product"]' ... '>
>>> selector.xpath('.//*[@itemprop="name"][1]/text()').extract()
[u'l fun broadband clean people brompton european']

我们可以在Selector对象表中用for循环提取一个索引页的所有30个项目信息。还是从第3章中的maunal.py文件开始,重命名为fast.py。重复使用大部分代码,修改parse()和parse_item()方法。更新的方法如下所示:

def parse(self, response):
    # Get the next index URL and yield Requests
    next_sel = response.xpath('//*[contains(@class,"next")]//@href')
    for url in next_sel.extract():
        yield Request(urlparse.urljoin(response.url, url))
    # Iterate through products and create PropertiesItems
    selectors = response.xpath(
        '//*[@itemtype="http://schema.org/Product"]')
    for selector in selectors:
        yield self.parse_item(selector, response)

第一部分中用于产生下一条索引请求的代码没有变动。不同的地方是第二部分,我们重复使用选择器调用parse_item()方法,而不是用yield创建请求。这和原先使用的源代码很像:

def parse_item(self, selector, response):
    # Create the loader using the selector
    l = ItemLoader(item=PropertiesItem(), selector=selector)
    # Load fields using XPath expressions
l.add_xpath('title', './/*[@itemprop="name"][1]/text()',
                MapCompose(unicode.strip, unicode.title))
    l.add_xpath('price', './/*[@itemprop="price"][1]/text()',
                MapCompose(lambda i: i.replace(',', ''), float),
                re='[,.0-9] ')
    l.add_xpath('description',
                './/*[@itemprop="description"][1]/text()',
                MapCompose(unicode.strip), Join())
    l.add_xpath('address',
                './/*[@itemtype="http://schema.org/Place"]'
                '[1]/*/text()',
                MapCompose(unicode.strip))
    make_url = lambda i: urlparse.urljoin(response.url, i)
    l.add_xpath('image_URL', './/*[@itemprop="image"][1]/@src',
                MapCompose(make_url))
    # Housekeeping fields
    l.add_xpath('url', './/*[@itemprop="url"][1]/@href',
                MapCompose(make_url))
    l.add_value('project', self.settings.get('BOT_NAME'))
    l.add_value('spider', self.name)
    l.add_value('server', socket.gethostname())
    l.add_value('date', datetime.datetime.now())
    return l.load_item()

我们做出的变动是:

  • ItemLoader现在使用selector作为源,不使用Response。这么做可以让ItemLoader更便捷,可以让我们从特定的区域而不是整个页面抓取信息。
  • 通过在前面添加“.”使XPath表达式变为相关XPath。

提示:碰巧的是,在我们的例子中,XPath表达式在索引页和介绍页中是相同的。不同的时候,你需要按照索引页修改XPath表达式。

  • 在response.url给我们列表页的URL之前,我们必须自己编辑Item的URL。然后,它才能返回我们抓取网页的URL。我们必须用.//*[@itemprop="url"][1]/@href提取URL,然后将它用MapCompose转化为URL绝对路径。

这些小小大量的工作的改动可以节省大量的工作。现在,用以下命令运行爬虫:

$ scrapy crawl fast -s CLOSESPIDER_PAGECOUNT=3
...
INFO: Dumping Scrapy stats:
   'downloader/request_count': 3, ...
   'item_scraped_count': 90,...

就像之前说的,我们用三个请求,就抓取了90个项目。不从索引开始的话,就要用93个请求。

如果你想用scrapy parse来调试,你需要如下设置spider参数:

$ scrapy parse --spider=fast http://web:9312/properties/index_00000.html
...
>>> STATUS DEPTH LEVEL 1 <<<
# Scraped Items  --------------------------------------------
[{'address': [u'Angel, London'],
... 30 items...
# Requests  ---------------------------------------------------
[<GET http://web:9312/properties/index_00001.html>]

正如所料,parse()返回了30个Items和下一个索引页的请求。你还可以继续试验scrapy parse,例如,设置—depth=2。

 

澳门新萄京官方网站 17

澳门新萄京官方网站 18浏览器自带工具

可以抓取Excel文件的爬虫

大多数时候,你每抓取一个网站就使用一个爬虫,但如果要从多个网站抓取时,不同之处就是使用不同的XPath表达式。为每一个网站配置一个爬虫工作太大。能不能只使用一个爬虫呢?答案是可以。

新建一个项目抓取不同的东西。当前我们是在ch05的properties目录,向上一级:

$ pwd
/root/book/ch05/properties
$ cd ..
$ pwd
/root/book/ch05

新建一个项目,命名为generic,再创建一个名为fromcsv的爬虫:

$ scrapy startproject generic
$ cd generic
$ scrapy genspider fromcsv example.com

新建一个.csv文件,它是我们抓取的目标。我们可以用Excel表建这个文件。如下表所示,填入URL和XPath表达式,在爬虫的目录中(有scrapy.cfg的文件夹)保存为todo.csv。保存格式是csv:

澳门新萄京官方网站 19

一切正常的话,就可以在终端看见这个文件:

$ cat todo.csv 
url,name,price
a.html,"//*[@id=""itemTitle""]/text()","//*[@id=""prcIsum""]/text()"
b.html,//h1/text(),//span/strong/text()
c.html,"//*[@id=""product-desc""]/span/text()"

Python中有csv文件的内建库。只需import csv,就可以用后面的代码一行一行以dict的形式读取这个csv文件。在当前目录打开Python命令行,然后输入:

$ pwd
/root/book/ch05/generic2
$ python
>>> import csv
>>> with open("todo.csv", "rU") as f:
        reader = csv.DictReader(f)
        for line in reader:
            print line

文件的第一行会被自动作为header,从而导出dict的键名。对于下面的每一行,我们得到一个包含数据的dict。用for循环执行每一行。前面代码的结果如下:

{'url': ' http://a.html', 'price': '//*[@id="prcIsum"]/text()', 'name': '//*[@id="itemTitle"]/text()'}
{'url': ' http://b.html', 'price': '//span/strong/text()', 'name': '//h1/text()'}
{'url': ' http://c.html', 'price': '', 'name': '//*[@id="product-desc"]/span/text()'}

很好。现在编辑generic/spiders/fromcsv.py爬虫。我们使用.csv文件中的URL,并且不希望遇到域名限制的情况。因此第一件事是移除start_URL和allowed_domains。然后再读.csv文件。

因为从文件中读取的URL是我们事先不了解的,所以使用一个start_requests()方法。对于每一行,我们都会创建Request。我们还要从request,meta的csv存储字段名和XPath,以便在我们的parse()函数中使用。然后,我们使用Item和ItemLoader填充Item的字段。下面是所有代码:

import csv
import scrapy
from scrapy.http import Request
from scrapy.loader import ItemLoader
from scrapy.item import Item, Field
class FromcsvSpider(scrapy.Spider):
    name = "fromcsv"
def start_requests(self):
    with open("todo.csv", "rU") as f:
        reader = csv.DictReader(f)
        for line in reader:
            request = Request(line.pop('url'))
            request.meta['fields'] = line
            yield request
def parse(self, response):
    item = Item()
    l = ItemLoader(item=item, response=response)
    for name, xpath in response.meta['fields'].iteritems():
        if xpath:
      item.fields[name] = Field()
            l.add_xpath(name, xpath)
    return l.load_item()

运行爬虫,输出文件保存为csv:

$ scrapy crawl fromcsv -o out.csv
INFO: Scrapy 0.0.3 started (bot: generic)
...
DEBUG: Scraped from <200 a.html>
{'name': [u'My item'], 'price': [u'128']}
DEBUG: Scraped from <200 b.html>
{'name': [u'Getting interesting'], 'price': [u'300']}
DEBUG: Scraped from <200 c.html>
{'name': [u'Buy this now']}
...
INFO: Spider closed (finished)
$ cat out.csv 
price,name
128,My item
300,Getting interesting
,Buy this now

有几点要注意。项目中没有定义一个整个项目的Items,我们必须手动向ItemLoader提供一个:

item = Item()
l = ItemLoader(item=item, response=response)

我们还用Item的fields成员变量添加了动态字段。添加一个新的动态字段,并用ItemLoader填充,使用下面的方法:

item.fields[name] = Field()
l.add_xpath(name, xpath)

最后让代码再漂亮些。硬编码todo.csv不是很好。Scrapy提供了一种便捷的向爬虫传递参数的方法。如果我们使用-a参数,例如,-a variable=value,就创建了一个爬虫项,可以用self.variable取回。为了检查变量(没有的话,提供一个默认变量),我们使用Python的getattr()方法:getattr(self, 'variable', 'default')。总之,原来的with open…替换为:

with open(getattr(self, "file", "todo.csv"), "rU") as f:

现在,todo.csv是默认文件,除非使用参数-a,用一个源文件覆盖它。如果还有一个文件,another_todo.csv,我们可以运行:

$ scrapy crawl fromcsv -a file=another_todo.csv -o out.csv

咳咳咳.....接下来咱们就进入正题!

可以看见,Query String Parameters.对应是个字典,也可以通过键值对的形式改变字典pageNo的值,来达到访问不同评论网址的目的。下面就是爬取网站内容的工作了,这就是我找隐藏网址的过程。

然后我们点击确定,浏览器会记录下刚才的网络请求,如下图

总结

在本章中,我们进一步学习了Scrapy爬虫。我们使用FormRequest进行登录,用请求/响应中的meta传递变量,使用了相关的XPath表达式和Selectors,使用.csv文件作为数据源等等。

接下来在第6章学习在Scrapinghub云部署爬虫,在第7章学习关于Scrapy的设置。


序言
第1章 Scrapy介绍
第2章 理解HTML和XPath
第3章 爬虫基础
第4章 从Scrapy到移动应用
第5章 快速构建爬虫
第6章 Scrapinghub部署
第7章 配置和管理
第8章 Scrapy编程
第9章 使用Pipeline
第10章 理解Scrapy的性能
第11章(完) Scrapyd分布式抓取和实时分析


首先,进入半次元,点击COS,热门推荐

总结一下,我们就是在找动态网页的时候通过打开开发者选项(F12),找到要爬取网页文件的header,在Query String Parameters中找到对应的参数部分,最后将url主体部分和参数部分结合一起就能得到完整的url地址了。

澳门新萄京官方网站 20澳门新萄京官方网站快速构建爬虫,爬取动态网页时遇到的问题。投硬币拦截的包

澳门新萄京官方网站 21

下面附一下爬取的代码:

这一个add就是我们刚才投硬币的网络请求了,我们来分析一下这个请求的内容。

 

 1 from bs4 import BeautifulSoup
 2 import requests
 3 import re
 4 import pandas as pd
 5 
 6 #太平洋网爬取小米6X的评论
 7 #动态网页爬取(ajax)
 8 
 9 
10 def getHtml(url,data): #只输入URL的主体部分,后面的参数用下面的字典附加上
11     try:
12         r=requests.get(url,params=data)
13         r.raise_for_status()
14         r.encoding=r.apparent_encoding
15         return r.text
16     except:
17         print('爬取失败')
18 
19 def getComment(html):#获得一页的评论
20     commentList=[]
21     soup=BeautifulSoup(html,'html.parser')
22     lines=soup.find_all('dl',attrs={'class':'cmt-content'})#获得一整页所有的评论总的标签内容
23     for line in lines:#对每个评论进行解析,line就是每个评论的总标签内容<di class=cmt_content...>  ...</dl>
24         goal=line.find('strong',attrs={'class':'goal'}).string#得到总评分
25         comm_totall=line.find('div', attrs={'class':'eval-star'}).p.string.strip()#总评价
26         catagory=line.find('ul',attrs={'class':'goal-detail'}).find_all('li')#获得几个属性的评价
27        # print(catagory)
28         a1=catagory[0].string
29         a2 = catagory[1].string
30         a3 = catagory[2].string
31         a4 = catagory[3].string
32         a5 = catagory[4].string
33         comm_detail=line.find('p',attrs={'class':"text"})#具体评价,但这部分内容存在标签与字混合的成分,要把标签替换掉
34         detail_new=re.sub(r'<.*?>','',str(comm_detail))#因为部分内容存在空格xa0,要去掉这部分空格的代码显示
35         detail=','.join(detail_new.split())#用逗号来将分割的字符串两节起来,join()函数用来连接字符串数组元素
36         commentList.append([goal,comm_totall,a1,a2,a3,a4,a5,detail])
37     return commentList
38     # print(commentList)
39 
40 def comment(url,num):#获得多个页面的评论
41     data={'productId': 1073867,
42     'filterBy': -1,
43     'itemCfgId': -1,
44     'order': 2,
45     'pageNo': 1,
46     'vId': 432764}
47     comment_all=[]
48     for i in range(1,num 1):
49         data['pageNo']=i
50         html=getHtml(url,data)
51         comment=getComment(html)
52         comment_all =comment
53         print('页数',i)
54     #print(comment_all)
55     return comment_all
56 
57 if __name__=='__main__':
58     url='http://pdcmt.pconline.com.cn/front/2015/mtp-list.jsp?'
59     a=comment(url,17)
60     print(len(a))
61     name = ['总评分', '总评价','性价比','屏幕','流畅度','电池','相机','细评']
62     test = pd.DataFrame(columns=name, data=a)
63     test.to_csv('D:/mi6x.csv', index=False)  # 去掉默认的行索引index

首先有一个Request URL,就是前面提到的请求目标api,这个操作就是向这个网址发起post请求。

点击F12,可以看到开发者工具窗口

 

然后有一个Form Data,它记录了我们投币的视频id,投币数量,还有一个csrf我也不知道是什么,可能是用来身份验证的。

澳门新萄京官方网站 22

 

Request Headers中,我们可以找到我们在该网站的Cookie,如下图

 

澳门新萄京官方网站 23cookie

我们以第一张COS照片的代码进行分析....额...第二张好看,还是从第二张开始吧。

有了这三个东西,我们就可以不用浏览器,直接使用其他的软件完成投币操作了。

红框里面就是这张图片的html代码,然后我们以正常访问方式点击图片进入网页,可以看到这张图片分辨率更高。

打开我们的网络请求软件,将这三个参数依次复制进去(记得点击view source后复制原始文字),我们更换一下aid,这里随便找了个视频,aid=33615324,点击一下测试按钮发送一次网络请求,结果如下:

澳门新萄京官方网站 24

澳门新萄京官方网站 25投币结果

 

这里我请求了一个已经投过币的视频,返回结果显示无法再投币了,说明起作用了。

我们与之前HTML代码的图片的URL进行比较

再以jd的购物为例,这个请求方式不同于常规,使用了Query String Parameters的形式。

澳门新萄京官方网站 26

首先随便加入一个东西到购物车,我们可以看见请求的参数是Query String Parameters,而并没有form data,说明这个方式是将参数拼接在目标网址后面的。

 

pid代表商品id,pcount代表数量,ptype不知..于是,我们现在有了RequestURL,Cookie,以及Parameters。

可以看见,2X3是我们第一次进网页时第一张COS照片得到的URL,w650是进入COS照片详细页面后得到的URL,发现他们的区别是URL代码中的最后一段。

只要我们更换pid,我们就能将其他的商品通过网络请求的方式加入我们的购物车了,现在来试一下。

其他COS照片以此类推

澳门新萄京官方网站 27加入购物车的请求内容

我们在第一次进入的页面继续往下滑,发现该网页滚到结尾时自动更新,可以确定网页使用了AJAX技术,我们回到置顶刷新界面,等网页加载好后按F12打开开发者工具,操作如图

可以看见URL里有很多? & =这样的字符,说明不是formData的形式,于是我们只需要把URL和Cookie复制进去就行了。

澳门新萄京官方网站 28

澳门新萄京官方网站 29模拟加入购物车

 

我们点击开始,进行持续请求,每个50毫秒请求一次(可以配合定时进行抢商品)。可以看见反回了一堆html代码,其实就是告诉你成功加入了购物车。现在我们去购物车看一看,确实是加入了。

点击XHR

澳门新萄京官方网站 30

我们继续往下划,等到页面更新时发现新条码 点击条目

通过这个原理,在秒杀的时候,我们只需要预先找一下商品的pid,减小一点间隔(太快了或者持续太久可能会有风险),就能设置个定时,愉快地自动加入购物车了。

澳门新萄京官方网站 31

 

在Headers页面往下滑,看见X-Reauested-With:XMLHttpRequest,表明是AJAX请求,找到Query String Parameters,这就是AJAX请求的数据,在Preview中可以看见AJAX返回的数据。

继续往下划,让网页数据更新,发现Network中又新出现的几个新条目

我们比较Query String Parameters的AJAX请求数据,发现

  1. grid_type:
  2. flow
  3. sort:
  4. hot

3.tag_id:

399

这三条数据和其他Network条目是相同的,但是since不相同,和其他条目对比

实现代码

如果你需要一个良好的学习交流环境,那么你可以考虑Python学习交流群:548377875;
如果你需要一份系统的学习资料,那么你可以考虑Python学习交流群:548377875。

澳门新萄京官方网站 32

 

效果

澳门新萄京官方网站 33

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:澳门新萄京官方网站快速构建爬虫,爬取动态网

关键词: