学习爬虫,最基础的便是模拟浏览器向服务器发出请求 。
实例引入
模拟发送一个请求,把网页的源代码获取下来。
可以利用requests库中的get方法来获取网页中的信息,为进一步提取所需信息做准备。
例如:
1 2 3 4 5 6 7 8 9 import requestsimport ioimport syssys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8' ) url = 'https://oi-wiki.org/' r = requests.get(url) print(r) print(r.text)
该代码会将https://oi-wiki.org/网页内容爬取并输出。
基本知识
GET请求
1 2 3 4 5 6 7 import requestsurl = 'http://httpbin.org/get' r = requests.get(url) print(r) print(r.text)
运行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 <Response [200]> { "args" : {}, "headers" : { "Accept" : "*/*" , "Accept-Encoding" : "gzip, deflate" , "Host" : "httpbin.org" , "User-Agent" : "python-requests/2.24.0" , "X-Amzn-Trace-Id" : "Root=1-600e6a30-263a11523bc6ff097314f31d" }, "origin" : "140.250.245.147" , "url" : "http://httpbin.org/get" }
当然,我们也还可以在GET请求时增加一些参数,如下:
http://httpbin.org/get?name=rain&university=XDU。
在get方法中,我们可以指定params参数来达到传递参数的效果。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 import requestsparams = { 'name' : 'rain' , 'university' : 'XDU' } url = 'http://httpbin.org/get' r = requests.get(url, params=params) print(r) print(r.text)
结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <Response [200]> { "args" : { "name" : "rain" , "university" : "XDU" }, "headers" : { "Accept" : "*/*" , "Accept-Encoding" : "gzip, deflate" , "Host" : "httpbin.org" , "User-Agent" : "python-requests/2.24.0" , "X-Amzn-Trace-Id" : "Root=1-600e6b0c-13dea24830332ab92ef3cc91" }, "origin" : "140.250.245.147" , "url" : "http://httpbin.org/get?name=rain&university=XDU" }
观察发现,返回内容为json格式,我们可以直接利用json()方法将该文本转化为字典。如下:
1 2 3 4 url = 'http://httpbin.org/get' r = requests.get(url, params=params) dict = r.json() print(dict)
但是当返回格式不是json时,会抛出异常。
提取信息
我们可以利用正则表达式获取所虚信息,如:
1 2 3 4 5 6 7 8 9 10 import requestsimport reurl = 'http://static1.scrape.cuiqingcai.com/' r = requests.get(url, verify=False ) print(r) pattern = re.compile('<h2.*?>(.*?)</h2>' , re.S) tittle = re.findall(pattern, r.text) print(tittle)
结果为:
1 ['霸王别姬 - Farewell My Concubine' , '这个杀手不太冷 - Léon' , '肖申克的救赎 - The Shawshank Redemption' , '泰坦尼克号 - Titanic' , '罗马假日 - Roman Holiday' , '唐伯虎点秋香 - Flirting Scholar' , '乱世佳人 - Gone with the Wind' , '喜剧之王 - The King of Comedy' , '楚门的世界 - The Truman Show' , '狮子王 - The Lion King' ]
代码参数的verify则是省去网站认证。
抓取二进制数据
图片、音频、视频这些文件本质上都是由二进制码组成,想要抓取它们,就要拿到它们的二进制数据。
例如我们想要抓取github的图标,网址为:https://github.com/favicon.ico。
代码如下:
1 2 3 4 5 6 import requestsurl = 'https://github.com/favicon.ico' r = requests.get(url) print(r.text) print(r.content)
结果如下:
1 2 :�������O b'\x00\x00\x01\x00\x02\x00\x10\x10\x00\x00\x01\x00 \x00(\x05\x00\x00&\x00\x00\x00
前者出现乱码,后者结果带有一个b,这代表是byte类型的数据。
通过以下代码保存图片:
1 2 3 4 5 6 import requests url = 'https://github.com/favicon.ico' r = requests.get(url) with open('favicon.ico', 'wb') as f: f.write(r.content)
某些网站会检查请求的headers信息,在不设置headers时,某些网站可能拒绝访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 import requestsheaders = { 'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/87.0.4280.141 Safari/537.36' } url = 'https://movie.douban.com/top250' r = requests.get(url, headers=headers) print(r) print(r.text)
当不设置headers时,豆瓣会拒绝访问。
POST请求
利用requests.post()方法即可。
高级用法
文件上传
1 2 3 4 5 import requestsfiles = {'file' : open('favicon.ico' , 'rb' )} r = requests.post('http://httpbin.org/post' , files=files) print(r.text)
Cookies
1 2 3 4 5 6 7 import requestsurl = 'http://www.baidu.com' r = requests.get(url) print(r.cookies) for key, value in r.cookies.items(): print(key + ": " + value)
结果如下:
1 2 <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]> BDORZ: 27315
利用Cookies可以模拟登录:
1 2 3 4 5 6 7 8 9 import requestsheaders = { 'Cookie' : 'Github中的Cookies' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/87.0.4280.141 Safari/537.36' } url = 'https://github.com/' r = requests.get(url, headers=headers) print(r.text)
结果如下:
1 2 3 ... <meta name ="user-login" content ="XdBirdie" > ...
发现存在含有用户特征的信息,说明我们模拟了登录的状态。
Cookie还可以通过下面的方法设置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import requestscookies = 'Github中的Cookies' headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/87.0.4280.141 Safari/537.36' } jar = requests.cookies.RequestsCookieJar() for cookie in cookies.split(';' ): key, value = cookie.split('=' ) print(key, value) jar.set(key, value) url = 'https://github.com/' r = requests.get(url, cookies=jar, headers=headers) print(r.text)
可以达到同样的效果。
Session维持
考虑如下代码:
1 2 3 4 5 6 import requestsurl = 'http://httpbin.org/cookies' r = requests.get(url + '/set/number/12345678' ) r = requests.get(url) print(r.text)
输出结果为:
但是利用Session:
1 2 3 4 5 url = 'http://httpbin.org/cookies' s = requests.Session() s.get(url + '/set/number/12345678' ) r = s.get(url) print(r.text)
输出结果为:
1 2 3 4 5 { "cookies" : { "number" : "12345678" } }e4
SSL证书验证
现在很多网站都要求使用HTTPS协议,但是有些网站可能并没有设置好HTTPS证书,或者网站的HTTPS证书不被认可。这时,这些网站可能就会出现SSL证书错误的提示。
可以使用verify参数控制是否验证证书,如果将其设置为False,在请求时就不会再验证证书是否有效。否则默认值为True,会自动验证。
超时设置
当客户端或者服务器网络响应延迟较高甚至无响应时,为防止服务器不能及时响应,应该设置一个超市时间,当超出此事件还未响应时,报错。
设置timeout参数即可。
例如:
1 2 3 4 import requestsurl = 'http://httpbin.org/get' r = requests.get(url, timeout=1 ) print(r.text)
然而链接分为两个阶段,链接阶段(connect)和传送阶段(read time),前面设置的timeout设置的时间是两段时间之和,也可以选择分别设置时间限。如下:
1 2 3 4 import requestsurl = 'http://httpbin.org/get' r = requests.get(url, timeout=(0.4 , 0.6 )) print(r.text)
如果想永久等待,可以直接将timeout设置为None,或者不设置,因为默认值为None。
身份认证
可以使用requests自带的身份认证功能,通过auth参数即可设置。
例如:
1 2 3 4 5 6 7 import requestsfrom requests.auth import HTTPBasicAuthurl = 'https://static3.scrape.cuiqingcai.com/' r = requests.get(url, auth=HTTPBasicAuth('admin' , 'admin' ), verify=False ) print(r.status_code) print(r.text)
但是相对繁琐,所以python提供了另一种方式进行身份认证:
1 2 3 4 5 6 import requestsurl = 'https://static3.scrape.cuiqingcai.com/' r = requests.get(url, auth=('admin' , 'admin' ), verify=False ) print(r.status_code) print(r.text)
requests还提供了其他认证方式,如OAuth认证,不过需要安装oauth包。
1 pip3 install requests_oauthlib
代理设置
对于大规模并且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面,更有甚者可能会直接封禁客户端的IP,导致一定时间段内无法访问。
为了防止这种情况发生,需要设置代理来解决问题,这是就需要用到proxies参数。