一,预备知识
(1)统一资源定位符
爬虫爬取的对象是网络资源,如果把互联网比作一个城市,互联网中许许多多的网络资源就像是城市中许许多多的的住户。若要拜访某家住户,就必须知道这家的地址。
当我们使用浏览器打开一个网页时,会发现网址栏:http://www.*****.com
我们平时说的网址,一般指www.*****.com这一部分。
那么前面的http是干什么的?它是一种常见的协议类型----超文本传输协议(Hyper Text Transfer protocol )的英文缩写。协议对应网络资源的访问方法(还按照上面例子,协议就是你拜访某家住户时,时要敲门还是按门铃,是用钥匙还是输入密码)。
协议加上网址,就是一个完整的统一资源定位符(Uniform Resource Locator),简称url。url是指每一网络资源在互联网上的唯一地址,有着统一的格式。
有时候,我们网址的开头并不是http,而是https。https是超文本传输协议安全的缩写,s是指安全(secure)。
超文本传输协议是一种请求/响应式的协议,在这种协议下,当客户端和服务器建立连接后,会向服务器发送一个请求,请求以某种方式获取服务器上的指定资源;在服务器接受到这个请求后,就会给客户端一个回应,给予相应的信息。这就是网络资源传输过程。
超文本传输协议定义了八种对网络资源的操作方式,爬虫过程中常用的就是GET和POST
有了统一资源定位符url,爬虫这个客户端/软件就可以通过向服务器发送一个http的GET请求获取网络资源了。这个网络资源是以超文本标记语言(html)格式表示的。
(2)超文本标记语言(html)
电脑上的浏览器读取使用html语言写的文件,就可以呈现出网页五彩缤纷的样子。
标准的html文件都具有一个基本的整体结构,里面标签一般都是成对出现。通常以不带 /的 <> 作为开头,比如(
),以带 / 的 > 作为结尾(比如),然后夹在开头和结尾中间的就是资源的内容。
爬虫或者浏览器对服务器发送的一次请求,会得到一个完整的html回复,是一个完整的html文件。这个html文件使用和分别标志着超文本标记语言的开始和结束。在这一对标签之间,是网页的具体内容。
head标签标识着网页的头部信息。头部信息中包含页面的标题,序言,说明等内容。头部信息使用标签
来表示。
在使用浏览器打开html文件时,头部信息不作为网页的主题内容显示。
比如之前提到的title,可以用于定义网页的标题,它的内容显示在网页窗口的标题栏中。例如如下所示。
主体内容则是网页浏览器中显示的实际内容,使用标签
来表示。
(3)Python实现爬虫
我们知道在用浏览器查看网络资源时,只需要把url输入到网址栏就可以看到网页的内容了。这是因为浏览器可以通过解析html标签,将html文件显示为我们看到的网页。
那么Python爬虫,该如何通过url找到对应的资源呢?又如何把html中的信息提取出来?
这就要用到Python的一些开源模块了,比如我们可以使用 requests 和 urllib 模块获取html文件;再使用 bs4 模块中的 BeautifulSoup类 把 html 文件中的内容提取出来。
二,发送网络请求
在文本传输协议下,想要获取 html 文件,其实就是要让爬虫向服务器发送一个请求,这个过程叫做网络请求,在Python中,我们可以使用一个叫做requests的模块实现网络请求。因为,要首先导入 import requests导入这个模块。
(1)GET请求
对于一般静态网页,完成页面请求的过程通常是:先确认需要获取内容url地址,然后向这个地址发送GET请求,获取到服务器以html格式表示的相应内容。
我们可以这样获取拉勾网上搜索python之后得到的结果页面的url。
获取页面的url
GET请求
运行程序后我们可以看到,我们获取的html文件内容非常地短,头部信息看起来没有大问题,但是body部分里找不到任何有用信息并且存在一部分乱码。这是为什么呢?
这是因为我们尝试请求的页面并不是简单的静态页面,里面有许多的动态脚本。那我们该怎么办呢?
(2)POST请求
与GET不同,POST是一个发布请求。当客户端向服务器发出POST请求时,意味着我们在试图向服务器提交一些数据。服务器对于客户端发来的POST请求,也会给予反馈,并且通过POST可以传递的信息比GET更多。
当我们在拉勾网的页面上输入查询关键词python,并提交查询请求时,网页端其实向服务器端连续发起了多个请求,最关键的是:
1,通过GET请求,获取结果页面的主体内容(html)
2,通过POST请求,获取职位列表的详细内容。
爬虫需要模拟的是浏览器的行为,因此,编写爬虫程序要从研究浏览器的网络请求开始。
做以下两个步骤操作:
1,打开浏览器,打开开发者工具(按键盘上的F12键)。
2,访问拉勾网主页(www.lagou.com),在职位搜索框中输入关键字python,并进行搜索。
F12开发者模式
在第一步打开开发者工具之后,点击右上角的Network选项, 然后再进行第二步的职位搜索操作。Network选项里记录着当前网页所有的网络请求。
仔细查看positionAjax.json
POST请求
虽然我们只发送了一个POST请求,但它依然提示我们操作太频繁。这是因为你被认出来了!服务器发现了发送请求的并不是浏览器客户端而是一个爬虫程序。
这就是所谓的反爬虫,爬虫和反爬虫的斗争就像病毒和反病毒一样,是一场持久战。这里的反爬虫规则简单地说就是拉勾网会想尽办法去分辨发送请求的到底是人还是机器,如果是人就给予正常的回应,如果是机器就返回错误信息。
网络服务器通常通过网络请求中的请求头来区分它接收到的请求是不是合法的。因此,爬虫可以在发起网络请求时设置一个正确的请求头,把自己伪装成一个浏览器。
request模块中的post方法中有个叫headers的参数,在调用post参数时,将其设置成为正确的消息头,就可以将这条信息伪装成浏览器发送的。因此,request.post(request_url, headers)。
Headers请求头信息
点开之后,首先是一个Referer,它也是一个url。(https://www.lagou.com/jobs/list_python后面再跟些内容)
Request url(https://www.lagou.com/jobs/positionAjax.json后面再跟些内容)是不一样的。
Referer表示当前发起的这个请求的来源是哪里。我们可以注意到 list_python 的url就是有搜索框的拉勾网的页面网址,positionAjax 就是职位搜索的请求地址。
服务器通过Referer判断一个网络请求的来源是不是正常的,就是职位请求得从搜索框页面发来,而不是凭空而来。
然后再来看User-Agent,这个东西是客户的身份标识,也是爬虫程序伪装程用户的重要元素。
除了以上两项,还有一个最重要的参数:Cookies。在我们的案例中,用到的Cookies信息有X_HTTP_TOKEN、user_trace_token、JSESSIONID和SEARCH_ID这四部分。
向POST请求中添加Cookies信息:在发送POST请求之前,首先向服务器发送一个GET请求,这个请求可以发送给Referer url。服务器收到这个请求之后,会在回复的消息中带上一个Cookie。我们在程序中记录下这个Cookie,再发送POST请求时直接使用它就可以了。
好处:1,使用GET方法向Referer url先发起请求,在网络请求行为上完全模拟了先访问Referer url再访问Request url的动作。2,获取的Cookie都是新鲜的,不容易被服务器查觉这个请求来自爬虫。
GET请求向服务器获取Cookie
其中的 url 是指 Referer url 。my_headers是包含了User-Agent等内容的网络请求头部信息。
Post方法也为Cookie专门提供了一个参数,即为
requests.post(request_url, headers, cookies)
添加cookies,将输出转化为字典假如,我们要找的关于职位的信息在如下的红色部分。
结果是一个嵌套的字典(字典中的value又是字典),在这个嵌套字典数据结构中,依次索引以下的键:"content"-"positionResult"-"result"。
我们得到了所有职位信息,但是仔细查看,这些内容好像和Python没有多大关系。这是因为我们缺少了一个关键信息:职位关键词python。以至于把结果全部返回了。
查询关键词的参数
其中,Form Data,就包含了用户在网页上点搜索之后,浏览器通过表单提交方式向服务器提交的内容。比如:kd:python,就是这次用户输入的关键词。
另外一个栏目就是Query String Parameters,从上面截图中,看到它只定义了一个项目needAddtionalResult的内容。我们这次网页请求的Request url,是https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false,仔细对比一下,可以发现url中问号(?)后面的这个网址参数(needAddtionalResult=false)就是Query String Parameters的内容。