爬虫网络请求模块
前言
做过爬虫的同学基本都明白,爬虫其实就是那三板斧。第一,明确我们要爬取的网站。第二,向网站发起请求,分析网站数据结构,第三,爬取数据,保存数据。三板斧整完了,基本我们的爬虫需求就搞定了。在第二步的时候,我们需要向目标网站发起请求,这个就是Python无与伦比的优势了,因为它不仅有内置的网络请求模块urllib,还有大名鼎鼎的第三方网络请求模块requests。用过的都说好,今天我们就来学习一下,网络模块这一章相关的知识。
Python内置模块urllib
以前在Python2的时候向一个网站发起请求的时候需要导入urllib和urllib2非常的麻烦。在Python3中进行了一个整合。我们直接使用urllib就可以了。
urllib.request
- 常用的方法
- urllib.request.urlopen("网址") 作用 :向网站发起一个请求并获取响应
- 字节流 = response.read()
- 字符串 = response.read().decode("utf-8")
- urllib.request.Request"网址",headers="字典") urlopen()不支持重构User-Agent
import urllib.request
response = urllib.request.urlopen('https://www.baidu.com')
# read()方法把响应对象里面的内容读取出来
print(response.read())
执行结果
通过执行的结果我们不难看出,我们现在拿到的是一个字节流,也就是bytes类型的数据。那么这个时候我们可以通过decode()来把这个bytes类型的数据转换成str类型的数据
html = response.read().decode('utf-8')
print(type(html),html)
执行结果
通过这种方式我们就简简单单的像一个网站发起了请求,并获取了它的响应数据。接下里我们就要思考一下这个反爬。我们说最基本的反爬是User-Agent。但是 urlopen()这个方法是不支持u-a的。那下面我们来讲另外的一个方法,urllib.request.Request(添加User-Agent)
import urllib.request
# 请求百度的数据(网页源码)
url = 'https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
# 1. 创建请求对象(构建 User-Agent)
response = urllib.request.Request(url,headers=headers)
# 2. 获取响应对象(urlopen())
res = urllib.request.urlopen(response)
# 3. 读取响应对象的内容(read().decode('utf-8'))
html = res.read().decode('utf-8')
print(html)
现在我们就可以总结一下用法了
1、利用Request()方法构建请求对象
2、利用urlopen()方法获取响应对象
3、利用响应对象的read().decode("utf-8")获取内容
- 响应对象(response)的方法
- read() 读取服务器响应的内容
- getcode() 返回HTTP的响应码
- geturl() 返回实际数据的URL(防止重定向问题)
print(res.getcode())
print(res.geturl())
执行结果
urllib.parse
- 常用方法
- urlencode(字典)
- quote(字符串)
这两个方法有什么作用呢?我们知道浏览器是不识别中文的。虽然在网址上显示了中文,实际上是浏览器进行了处理。例如我们把这个网址在复制一下,通过PyCharm来看一下
这个是什么情况呢?我们在浏览器中请求一个网址的时候,浏览器会对这个url进行一个编码,除英文字母,数字和部分符号外,其它的全部使用百分号+十六进制进行编码。所以在编写代码的时候,我们有时候就需要手动的来对中文进行一下编码。
import urllib.parse
name = {'wd':'海贼王'}
name = urllib.parse.urlencode(name)
print(name)
r = '海贼王'
result = urllib.parse.quote(r)
print(result)
第三方网络请求模块requests
提前大名鼎鼎的requests模块,了解过爬虫的同学一定不会陌生。就像它的介绍一样,让HTTP服务人类。不多说,我们开始学习
安装
由于requests模块是第三方的,所以我们需要安装一下。在这里推荐使用换源的方式来进行安装,我们这里就以豆瓣源来举例了
pip install requests -i https://pypi.douban.com/simple
通过换源的方式进行安装就非常快了。准备工作做完之后,接下来就简单多了
request常用方法
- requests.get(网址)
import requests
# 发送请求获得响应结果
response = requests.get('https://www.baidu.com/')
print(response)
执行结果
这样我们就简简单单的向百度发起了一个请求,并得到了Response响应对象。它给我们返回了一个状态码。200的意思就是请求成功了。 我们这个get请求不仅仅能请求一个网站。还可以添加一个params参数。例如headers请求头
import requests
# 添加user-agent
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
# 发送请求获得响应结果
response = requests.get('https://www.baidu.com/',headers=headers)
print(response)
例如 我想要在url中传递中国,我们想到了需要用urlencode对它进行编码。但是在reqeusts模块中就没有那么复杂了。如下图
import requests
# 添加user-agent
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
kw = {'kw':'中国'}
# 发送请求获得响应结果
response = requests.get('https://www.baidu.com/',params=kw,headers=headers)
print(response.text)
执行结果
响应方法
我们想一个网站发起了请求,我想要获取网页的数据怎么办呢?其实这个也不难,requests模块都帮我们做到了
print(response.text) 返回的数据是str
print(response.content) 返回的数据是bytes
response.text这种方式虽然是可以获取到网页的数据,但是往往会出现中文乱码。这个时候我们就用另一种方式来获取网页的数据了response.content.decode('utf-8').这种获取网页源码的方式可以很好的解决中文乱码问题。
有的同学可能有疑问response.content不是返回的是字节流的数据嘛。那么怎么可能出现str类型的数据呢?
大家第一反应就是一个是打印的是字符串,一个打印的是字节流的数据。首先respons.content是直接从网站上抓取的数据,没有做任何的处理,也就是没有做任何的编码。其次 response.text它是requests模块将respons.content解码后得到的字符串。那同学们想想解码是不是需要一个指定方式啊。但是我们这里并没有指定一个解码方式,但是 requests库可以猜测我们的一个解码方式。所以你在使用response.text来查询响应内容的时候会出现乱码的情况。这个时候我们就可以用respons.content中来手动的指定解码 respons.content.decode(‘utf-8’)
import requests
# 添加user-agent
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
kw = {'kw':'中国'}
# 发送请求获得响应结果
response = requests.get('https://www.baidu.com/',params=kw,headers=headers)
print(response.content.decode('utf-8'))
requests发送post请求
刚才都是用requests发送的get请求。那么下面我们通过一个有道字典的案例来实现发送post请求。
post请求需要携带数据,这些数据一般是在form表单里面
这个就是我们表单里面的数据。这些数据是不会在url地址上面显示的。下面我们就通过requests模块发送post请求来携带数据制作一个小软件 下面直接附上代码
import requests
import json
key = input('请输入您要翻译的内容:')
data = {
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15880623642174',
'sign': 'c6c2e897040e6cbde00cd04589e71d4e',
'ts': '1588062364217',
'bv': '42160534cfa82a6884077598362bbc9d',
'doctype': 'json',
'version': '2.1',
'keyfrom':'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'
}
# 携带数据发送请求
res = requests.post(url,data=data,headers=headers)
res.encoding = 'utf-8'
# 获取数据
html = res.text
# 转化成字典类型
r_dict = json.loads(html)
# 数据解析
content = r_dict['translateResult'][0][0]['tgt']
print(content)
执行结果
Cookie
Cookie是一个非常重要的数据,它的作用集中体现在2个方面
- 模拟登录
- 有些网站做了Cookie反爬
那么究竟什么是Cookie呢?
下面来自网络引用
Cookie,有时候也用复数形式Cookies,这种是指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密);简单来说就是它能够把你在访问网站时的产生的一些行为信息给读取保存下来,常用的是我们在访问某些网页时提示我们是否需要保存用户名和密码,下次登录的时候能够自动登录,无需重新登录
Cookie 技术诞生以来,它就成了广大网络用户和 Web 开发人员争论的一个焦点。有一些网络用户,甚至包括一些资深的 Web 专家也对它的产生和推广感到不满,这并不是因为 Cookie 技术的功能太弱或其他技术性能上的原因,而是因为 Cookie 的使用对网络用户的隐私构成了危害。因为 Cookie 是由 Web 服务器保存在用户浏览器上的小文本文件,它包含有关用户的信息
大概了解了Cookie之后我们来看看它的第一个作用模拟登录
例如现在知乎处于一个登录的状态,并且选择的是热榜这一专栏
那么我们可以通过NetWork来找一下cookie。通过cookie信息来进行一个模拟登录
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
'cookie': '_xsrf=1SMkDEbBof93pTCRd5MmPz8cmmOuAsaU; _zap=3a8fd847-c5d4-45cf-84a3-24d508f580f6; _ga=GA1.2.2058930090.1594280819; d_c0="AICeuVa2jBGPTuvzpsC3VFkq3TulCqxCfNQ=|1594280816"; z_c0="2|1:0|10:1594901209|4:z_c0|92:Mi4xRjdYeENBQUFBQUFBZ0o2NVZyYU1FU1lBQUFCZ0FsVk4yWkQ5WHdBbzV5TkZwYUs4a0RpNWdRUms2Yy1OQlRkaER3|3e67794db7e5f5ec768144d12fdac5ddf9be6d575cf0da3081bd59c5fd132558"; tshl=; tst=h; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1600419464,1600765648,1600867068,1601108280; Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49=1601108280; _gid=GA1.2.809449579.1601108280; KLBRSID=9d75f80756f65c61b0a50d80b4ca9b13|1601108281|1601108278; SESSIONID=sP67fUKhcmoakcsAU5RzS0NBNUzVG9ocD2JR2F5BsgF; JOID=VF4SAULnQMqzo0LPa-OP2bVp1097lBH5j8oXhQaLLaTXwy68K9-9quisQ8tlyVRuZgOhBpkxYtdJhmXXDe_IHYo=; osd=V1wTC0_kQsu5rkHNaumC2rdo3UJ4lhDzgskVhAyGLqbWySO_Kd63p-uuQsFoylZvbA6iBJg7b9RLh2_aDu3JF4c='
}
url = 'https://www.zhihu.com/hot'
res = requests.get(url, headers=headers)
with open('zhihu.html','w',encoding='utf-8') as f:
f.write(res.text)
可以通过浏览器打开这个html文件
我们来看一下Cookie的第二个作用反爬
如下图是一个北京到上海的车次列表。这个车次列表是通过ajax请求得到的数据。
那么我们想通过爬虫得到这个车次列表该如何实现呢?第一种方式可以通过selenium,这个技术咱们在后面的文章会讲解。第二种方式来分析它的数据接口
经过分析数据在result里面
那么下面的事情就好办了,我们直接请求这个数据接口的url地址就可以了
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
url = 'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2020-11-27&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=SHH&purpose_codes=ADULT'
res = requests.get(url,headers=headers)
print(res.content.decode('utf-8'))
执行结果
这个结果明显不是我们想要的。这个时候我们加上cookie试试
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36','Cookie':'_uab_collina=159490169403897938828076; JSESSIONID=9CCC55A5791112A1D991D16D05B8DE6C; _jc_save_wfdc_flag=dc; _jc_save_fromStation=%u5317%u4EAC%2CBJP; BIGipServerotn=1206911498.38945.0000; BIGipServerpool_passport=149160458.50215.0000; RAIL_EXPIRATION=1606609861531; RAIL_DEVICEID=Q2D75qw5BZafd0LCbLz0B0CWC8cdKlDp8taGuqQjNvLGk3cYKCg1Y4KoXbWHpTmr6iY988VhF0wHULKY9RimC4dWVelVHcf94Q3FRxQ0LfbzRqvTvC19gq7XNKs0aQgeBhCZ5dVfllX8gW5GHSoeQ10di_JL7sLg; route=6f50b51faa11b987e576cdb301e545c4; _jc_save_toStation=%u4E0A%u6D77%2CSHH; _jc_save_fromDate=2020-11-27; _jc_save_toDate=2020-11-25'
}
url = 'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2020-11-27&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=SHH&purpose_codes=ADULT'
res = requests.get(url,headers=headers)
print(res.content.decode('utf-8'))
执行结果
Session
通过在服务端记录的信息确定用户身份。这里这个session就是一个指的是会话,并不是我们所说web中的那个session这里大家要理解清楚 首先说一下,为什么要进行会话保持的操作? requests库的session会话对象可以跨请求保持某些参数,说白了,就是比如你使用session成功的登录了某个网站,则在再次使用该session对象求求该网站的其他网页都会默认使用该session之前使用的cookie等参数
尤其是在保持登陆状态时运用的最多,在某些网站抓取,或者app抓取时,有的时强制登陆,有的是不登陆返回的数据就是假的或者说是不完整的数据,那我们不可能去做到每一次请求都要去登陆一下怎么办,就需要用到保持会话的功能了,我们可以只登陆一次,然后保持这种状态去做其他的或者更多的请