上一章我们使用Urllib来写网络爬虫,但是我们能发现,他的功能不是很足,因为比如网页验证,处理cookies等功能需要opener和handler来实现。现在我们使用更加强大的爬虫库Requests
首先安装这个库
在urllib库中,我们使用urlopen来请求网页,但是实际上就是使用了一个GET方法来请求网页,在requests中,直接使用get()方法:
import requests
r = requests.get('https://www.baidu.com/')
print(type(r)) # requests.models.Response类型
print(r.status_code) # 状态码
print(type(r.text)) # Response Body 的类型为一个字符串
print(r.text)
print(r.cookies)
除了使用get(),我们还可以:
r = requests.post('http://httpbin.org/post')
r = requests.put('http://httpbin.org/put')
r = requests.delete('http://httpbin.org/delete')
r = requests.head('http://httpbin.org/get')
r = requests.options('http://httpbin.org/get')
如果要给链接传递参数:
import requests
data = {
'name': 'germey',
'age': 22
}
r = requests.get("http://httpbin.org/get", params=data)
print(r.text)
网页的text虽然是字符串类型,但还是json格式,所以可以直接使用json()将其转换为字典格式:
r = requests.get("http://httpbin.org/get")
print(r.json())
抓取页面例子:抓取知乎页面所有问题
import requests
import re
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
# 这里要加浏览器标识信息,否则知乎会禁止抓取
r = requests.get("https://www.zhihu.com/explore", headers=headers)
pattern = re.compile('explore-feed.*?question_link.*?>(.*?)', re.S)
titles = re.findall(pattern, r.text)
print(titles)
抓取图片视频等二进制数据:
import requests
r = requests.get("https://github.com/favicon.ico")
print(r.text)
print(r.content)
第一行会出现乱码,第二行会出现byte类型数据。因为图片实际上是二进制数据,所以第一行将其直接转换为字符串会出错,那么我们如何将抓取到的图片保存下来呢?
import requests
r = requests.get("https://github.com/favicon.ico")
with open('favicon.ico', 'wb') as f:
# wb表示以二进制的方式写入文件
f.write(r.content)
import requests
data = {'name': 'germey', 'age': '22'}
r = requests.post("http://httpbin.org/post", data=data)
print(r.text)
返回结果中的form部分就是提交的数据,这就能证明POST请求成功了
上面我们使用了text和content来获取内容,其实还有以下属性和方法:
import requests
r = requests.get('http://www.jianshu.com')
print(type(r.status_code), r.status_code) #状态码
print(type(r.headers), r.headers) #请求头
print(type(r.cookies), r.cookies) #cookies
print(type(r.url), r.url)
print(type(r.history), r.history) #请求历史
结果如下:
200
{'X-Runtime': '0.006363', 'Connection': 'keep-alive', 'Content-Type': 'text/html; charset=utf-8', 'X-Content-Type-Options': 'nosniff', 'Date': 'Sat, 27 Aug 2016 17:18:51 GMT', 'Server': 'nginx', 'X-Frame-Options': 'DENY', 'Content-Encoding': 'gzip', 'Vary': 'Accept-Encoding', 'ETag': 'W/"3abda885e0e123bfde06d9b61e696159"', 'X-XSS-Protection': '1; mode=block', 'X-Request-Id': 'a8a3c4d5-f660-422f-8df9-49719dd9b5d4', 'Transfer-Encoding': 'chunked', 'Set-Cookie': 'read_mode=day; path=/, default_font=font2; path=/, _session_id=xxx; path=/; HttpOnly', 'Cache-Control': 'max-age=0, private, must-revalidate'}
, , ]>
http://www.jianshu.com/
[]
使用status code来判断请求是否成功:
import requests
r = requests.get('http://www.jianshu.com')
exit() if not r.status_code == requests.codes.ok else print('Request Successfully')
上面这个例子比较了返回码和内置的成功码,如果成功输出成功消息,失败则程序终止,这里requests.codes.ok
得到的状态码是200,其他的为:状态码
如果想判断结果是不是404 ,则使用requests.codes.not_found
文件上传:
import requests
files = {'file': open('favicon.ico', 'rb')}
r = requests.post('http://httpbin.org/post', files=files)
print(r.text)
网站返回Response,里面包含files字段,而form是空的,证明文件上传部分会有单独的Files字段来标识。
===========================================================
cookies:
urllib处理cookies的方式很复杂,但是Requests,获取和设置都非常的简单。有两种方法:
获取cookies方式:
import requests
r = requests.get('https://www.baidu.com')
print(r.cookies)
for key, value in r.cookies.items():
print(key + '=' + value)
>>> , ]>
BDORZ=27315
__bsi=13533594356813414194_00_14_N_N_2_0303_C02F_N_N_N_0
import requests
headers = {
'Cookie': 'q_c1=31653b264a074fc9a57816d1ea93ed8b|1474273938000|1474273938000',
'Host': 'www.zhihu.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
}
r = requests.get('https://www.zhihu.com', headers=headers)
import requests
cookies = '..........'
jar = requests.cookies.RequestsCookieJar()
headers = {
'Host': 'www.zhihu.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
}
for cookie in cookies.split(';'):
key, value = cookie.split('=', 1)
jar.set(key, value)
r = requests.get('http://www.zhihu.com', cookies=jar, headers=headers)
print(r.text)
=============================================================
会话维持:
在Requests中,我们直接使用get()或者post()方法可以模拟网页的请求,但是这实际上是不同的会话session,即相当于用了两个浏览器打开不同的页面,那么会遇到的问题是:第一次用post方法登录了页面,第二次使用get方法请求个人信息页面,但是由于实际上是打开了两个浏览器,所以第二次并不能获取成功(确实可以每次加上同样的cookies)。
其实解决上述办法的主要方式是维持同一个session,即每次打开浏览器的新的选项卡,而不是新浏览器:
import requests
s = requests.Session() # 这一行是重点,以后每次使用这个session对象
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)
=============================================================
SSL证书验证:
在Requests中,我们可以使用verify这个参数来控制是否验证参数,如果不加,默认验证证书。比如我们爬去12306,会提示SSLError的错误,解决方法:
import requests
response = requests.get('https://www.12306.cn', verify=False)
然后成功,但是会报出警告,我们尝试忽略这个警告:
from requests.packages import urllib3
urllib3.disable_warnings()
或者我们可以捕获警告到日志:
import logging
logging.captureWarnings(True)
============================================================
超时设置:
我们应当设置超时时间,不然我们会浪费很多时间去访问一个可能无响应的网站:
import requests
r = requests.get('https://www.taobao.com', timeout=1)
=============================================================
身份认证:
有时候访问网站,可能要求我们身份认证(不是那种网站的会员账号之类的登录),解决办法:
import requests
from requests.auth import HTTPBasicAuth
r = requests.get('http://localhost:5000', auth=HTTPBasicAuth('username', 'password'))
# 可以直接传递一个元组,也是上面的简化方法
r = requests.get('http://localhost:5000', auth=('username', 'password'))
============================================================
使用Prepared Request构建一个Request对象:
我的上一篇文章里面说到了Urilib可以将request表示为一个数据结构,这里我们也可以实现,这个数据结构就叫做Prepared Request:
from requests import Request, Session
url = 'http://httpbin.org/post'
data = {
'name': 'germey'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
}
s = Session()
req = Request('POST', url, data=data, headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)