网络爬虫也叫做网络机器人,可以代替人们自动地在互联网中进行数据信息的采集与整理。它是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,可以自动采集所有其能够访问到的页面内容,以获取相关数据。
爬虫的使用,能够在一秒内访问几十甚至几百次服务器,这种速度根本不是人所能达到的,因而也就给服务器加大了负担,如果持续这种访问量,甚至可能导致服务器崩溃,所以,各个网站对爬虫的访问都是有一些限制的和要求的。
在要求方面,各个网站提供了robots协议,里面规定了该网站中哪些部分能够进行爬虫访问,哪些部分不能进行爬虫访问,这也称为君子协议,不过好像大部分都是小人,不怎么想遵守,如果想要查看一个网站的robots协议,只需要在网站网址的后面加上 robots.txt
即可,比如想要查看CSDN的robots协议,只需要在CSDN的网址 https://www.csdn.net/
加上 robots.txt
,即输入网址 https://www.csdn.net/robots.txt
就可以看到下面的内容,意思是进禁止所有人访问该网站部分内容,还玩傲娇。
在限制方面,各大网站手段也是层出不穷,以前我不知道搞那些弱智的验证码有什么用,现在学了爬虫知道了,确实难受了一段时间,不过该行还是得行。反爬手段主要有以下几种:
用户向服务器发送信息称之为请求,服务器向用户发送信息称之为响应。请求一般由请求方法、请求网址、请求头、请求体组成。
请求方法
常见的请求方法如下:
GET:请求页面,数据包含在URL里面
POST:大多用于提交表单或者上传文件,数据包含在请求体中
HEAD:类似GET请求,不过响应报文没有具体的内容,用于获取报头
PUT:用客户端传送的数据取代指定的内容
DELETE:请求服务器删除指定的页面
CONNECT:把服务器当作跳板,让服务器代替客户端访问其他网页
OPTIONS:允许客户端查看服务器的性能
TRACE:回显服务器收到的请求,主要用于测试或者诊断
不过我们见到和使用的大多数都是GET和POST请求
请求网址
请求的网址即URL
请求头
请求头,一般是传送服务器需要的一些附加信息,其中比较重要的就是User-Agent,Referer,Cookie等,常用的请求有说明如下
Accept: 请求报头域,用于指定客户端可接受哪些类型的信息
Accept-Language: 指定客户端可接受的语言类型
Accept-Encoding: 指定客户端可接受的编码
Host:用于指定资源主机的IP和端口号,其内容为请求URL的原始服务器或网关的位置
Cookie:网站为了辨别用户进行会话跟踪而存储在用户本地的数据,它的主要功能是维持当前访问会话。
Referer: 用来标识这个请求是从哪个页面发过来的,服务器可以拿到这一信息并做相应的处理,如做资源统计,防盗链接处理等。
User-Agent: 可以是服务器识别客户端使用的操作系统及版本,浏览器及版本信息等。所以在做爬虫时要加上此信息,可以伪装浏览器;不加的话很容易被识别为爬虫。
Conten-Type:互联网媒体类型,用来表示具体请求中媒体类型信息;如text/html代表HTML格式,image/gif代表GIF图片,application/json代表JSON类型
请求体
请求体一般POST请求的时候才会有,因为GET请求的信息都在URL里。
响应状态码
状态码能够最基本的判定服务器对请求的响应情况,比如200就是请求成功,301就是重定向,404就是请求资源不存在,500就是服务器错误等,常见的一些如下:
200:请求成功,服务器已成功处理请求。
301: 重定向,请求的网页已经移动到新位置
400: 请求错误401: 未授权,请求没有进行身份验证或者验证未通过
403: 禁止访问404:未找到,请求资源不存在500:服务器错误
503: 服务器无法使用
响应头
响应头包含了服务器对请求的一些应答信息,如Server,Content-Type,Set-cookie等信息。
content-type: 返回数据的类型
sever:服务器名称,版本等信息
set-cookie: 会话cookie,下次请求需要带上。
响应体
响应信息中最重要的当属响应体了,因为我们想要获取的信息基本都在里面。python的request库也有对应的方法了提取相关信息,即 r.text
。
POST请求和GET请求都是请求的方式,其区别如下:
爬虫中很重要的一个库就是requests库,该库能够完全代替Python自带的urllib库,且使用起来更加简单高效。
GET请求我们可以拿百度来进行尝试。
从网址搜索后百度的网址可以看出来,我们的搜索信息都在网址后面,使用的是 wd=关键词
的形式,比如下面我搜索requests后,百度的网页显示如下:
这里的 wd
明显与我们搜索的关键词一致,因此,我们只需要拼接后即可进行搜索。
为了防止其进行反爬,我们需要模拟用户请求,即将网站请求头的一些信息加入到我们的requests请求中,网站的请求头信息可以按F12在Network中筛选Fetch/XHR找到。
当然,这里面并不是每个请求头都有用,起最大作用的是 user-agent
以及 Cookie
请求头。
代码如下:
import requests
# 在使用requests库时,可以不用在后面加?,其会自动添加
url = 'https://www.baidu.com/s'
data = {
'wd': '背景'
}
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
'Cookie': 'ORIGIN=2; ISSW=1; ISSW=1; BIDUPSID=F58D6799C8D928D5A89BE0274671EFA6; BD_UPN=12314753; BAIDUID=86EC4A79A69BC30551F1FD13B3AE7BA2:FG=1; PSTM=1662961767; BDUSS=JUbDcySUhQfjMtelJzYzd5cX5Kby1vfmFCMnFZWTBCTU10cnJ2SVBLbzJTRTlqRVFBQUFBJCQAAAAAAAAAAAEAAABcBQRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADa7J2M2uydjN3; BDUSS_BFESS=JUbDcySUhQfjMtelJzYzd5cX5Kby1vfmFCMnFZWTBCTU10cnJ2SVBLbzJTRTlqRVFBQUFBJCQAAAAAAAAAAAEAAABcBQRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADa7J2M2uydjN3; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; H_PS_PSSID=26350; BAIDUID_BFESS=86EC4A79A69BC30551F1FD13B3AE7BA2:FG=1; delPer=0; BD_CK_SAM=1; PSINO=1; BA_HECTOR=852gak0l80a4a10h848k817d1hr74qv1i; ZFY=jgTOVcYL:Bdg0DHAbUhXQBWwwekSdsO0e3M8I:AuGvUec:C; B64_BOT=1; channel=baidusearch; baikeVisitId=31de3916-22bc-4816-a9ab-4ebe4d94b9b2; COOKIE_SESSION=321_0_2_3_12_1_1_0_2_1_18_0_3221_0_0_0_1672670956_0_1672713052|9#0_1_1671682412|1; H_PS_645EC=5e1ejfIQh/o7iHoCJqcOElbwpqojGL7pDiZ4mELA5If6tWQt/KbIX56pKTgD5GbedAlsG2DnInR7; WWW_ST=1672713491580'
}
response = requests.get(url, params=data, headers=headers)
print(response.text)
这里我们寻找一个post请求的网页,百度翻译来进行讲解。
百度翻译肯定有一个请求是向服务器请求翻译的,我们只需要将其找出来,然后吧URL记录下来即可进行爬取。
通过我们一个单词一个单词的输入,我们可以发现,百度翻译的sug网页传递的就是我们的翻译请求的单词。然后复制下来该网页的Cookie值以及user-agent值到请求头,代码如下:
import requests
import json
url = 'https://fanyi.baidu.com/sug'
data = {
'kw': 'what'
}
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
'Cookie': 'BIDUPSID=F58D6799C8D928D5A89BE0274671EFA6; BAIDUID=86EC4A79A69BC30551F1FD13B3AE7BA2:FG=1; PSTM=1662961767; APPGUIDE_10_0_2=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDUSS=JUbDcySUhQfjMtelJzYzd5cX5Kby1vfmFCMnFZWTBCTU10cnJ2SVBLbzJTRTlqRVFBQUFBJCQAAAAAAAAAAAEAAABcBQRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADa7J2M2uydjN3; BDUSS_BFESS=JUbDcySUhQfjMtelJzYzd5cX5Kby1vfmFCMnFZWTBCTU10cnJ2SVBLbzJTRTlqRVFBQUFBJCQAAAAAAAAAAAEAAABcBQRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADa7J2M2uydjN3; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; H_PS_PSSID=26350; BAIDUID_BFESS=86EC4A79A69BC30551F1FD13B3AE7BA2:FG=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1672137088,1672154361,1672228903,1672714258; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1672714258; ab_sr=1.0.1_ZDgwZDczYmJmYmZlNGYxNGQ4MmE3M2Y5ODljNDhlNzI2ZWI4YmQ5MWZjOGZmZTUxYTcyMWUzOTIyMjc0Y2ZmMDM3MzRmMjVlMDgxYTRjOTBjYjVhNWU0YTgzNjA3OWZmMThiODNjYjUxM2RiM2EwZGVjZWIxNzllMzdhZDdkMGE4OTAxOTk1NTBmOGJhMjE2MzE0Nzc3ZjdkNzYyMGZiODVmYTAxMjE2ZDcyNTM4M2Y0ODkzMzI4NWM1NzMzZmRi'
}
response = requests.post(url, data=data, headers=headers)
# response.text 传递回来的编码有问题,需要用json将其转为‘utf-8’
obj = json.loads(response.text)
print(obj)
代理需要一个能用的IP,这样如果你的IP被网站封了,那么使用代理后网站那么就会显示你使用的是代理后的IP进行请求,就不会拒绝访问。由于免费代理不太靠谱,我又不想花钱,这里我就给大家演示个模板吧。
import requests
# 在使用requests库时,可以不用在后面加?,其会自动添加
url = 'https://www.baidu.com/s'
data = {
'wd': '背景'
}
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
'Cookie': 'ORIGIN=2; ISSW=1; ISSW=1; BIDUPSID=F58D6799C8D928D5A89BE0274671EFA6; BD_UPN=12314753; BAIDUID=86EC4A79A69BC30551F1FD13B3AE7BA2:FG=1; PSTM=1662961767; BDUSS=JUbDcySUhQfjMtelJzYzd5cX5Kby1vfmFCMnFZWTBCTU10cnJ2SVBLbzJTRTlqRVFBQUFBJCQAAAAAAAAAAAEAAABcBQRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADa7J2M2uydjN3; BDUSS_BFESS=JUbDcySUhQfjMtelJzYzd5cX5Kby1vfmFCMnFZWTBCTU10cnJ2SVBLbzJTRTlqRVFBQUFBJCQAAAAAAAAAAAEAAABcBQRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADa7J2M2uydjN3; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; H_PS_PSSID=26350; BAIDUID_BFESS=86EC4A79A69BC30551F1FD13B3AE7BA2:FG=1; delPer=0; BD_CK_SAM=1; PSINO=1; BA_HECTOR=852gak0l80a4a10h848k817d1hr74qv1i; ZFY=jgTOVcYL:Bdg0DHAbUhXQBWwwekSdsO0e3M8I:AuGvUec:C; B64_BOT=1; channel=baidusearch; baikeVisitId=31de3916-22bc-4816-a9ab-4ebe4d94b9b2; COOKIE_SESSION=321_0_2_3_12_1_1_0_2_1_18_0_3221_0_0_0_1672670956_0_1672713052|9#0_1_1671682412|1; H_PS_645EC=5e1ejfIQh/o7iHoCJqcOElbwpqojGL7pDiZ4mELA5If6tWQt/KbIX56pKTgD5GbedAlsG2DnInR7; WWW_ST=1672713491580'
}
# 设置代理
proxy = {
'http': '212.129.251.56:16896'
}
# 将代理放入请求
response = requests.get(url, params=data, headers=headers, proxies=proxy)
print(response.text)