(二)Requests

Requests概述:让 HTTP 服务人类

Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。
Requests库的优势 Requests 允许你发送纯天然,植物饲养的 HTTP/1.1 请求,无需手工劳动。你不需要手动为 URL 添加查询字串,也不需要对 POST 数据进行表单编码。Keep-alive 和 HTTP 连接池的功能是 100% 自动化的,一切动力都来自于根植在 Requests 内部的 urllib3。
为什么使用Requests库
  • requests在python2 和python3中通用,方法完全一样,urllib2在python2和python3中的名称不同
  • 工作中爬虫基本都使用requests
  • 虽然Python的标准库中 urllib 模块已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 "HTTP for Humans",说明使用更简洁方便。requests 继承了urllib的所有特性,requests的底层实现就是urllib2。
  • requests能够自动帮助我们解压(gzip压缩的等)网页内容,简单易用
  • Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码。
  • Requests库使用非常广泛,Twitter、Spotify、Microsoft、Amazon、Lyft、BuzzFeed、Reddit、NSA、女王殿下的政府、Amazon、Google、Twilio、Mozilla、Heroku、PayPal、NPR、Obama for America、Transifex、Native Instruments、Washington Post、Twitter、SoundCloud、Kippt、Readability、以及若干不愿公开身份的联邦政府机构都在内部使用。

    (二)Requests
    文章图片
Warning:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症、冗余代码症、重新发明轮子症、啃文档症、抑郁、头疼、甚至死亡:)。
功能特性 Requests 完全满足今日 web 的需求:
  • Keep-Alive & 连接池
  • 国际化域名和 URL
  • 带持久 Cookie 的会话
  • 浏览器式的 SSL 认证
  • 自动内容解码
  • 基本/摘要式的身份认证
  • 优雅的 key/value Cookie
  • 自动解压
  • Unicode 响应体
  • HTTP(S) 代理支持
  • 文件分块上传
  • 流下载
  • 连接超时
  • 分块请求
  • 支持 .netrc
  • Requests 支持 Python 2.6—2.7以及3.3—3.7,而且能在 PyPy 下完美运行。
开源地址:https://github.com/kennethreitz/requests
中文文档 API: http://docs.python-requests.org/zh_CN/latest/index.html
安装requests
$ pip install requests

基本GET请求(headers参数 和 parmas参数) (二)Requests
文章图片
最基本的GET请求可以直接用get方法
import requests resp = requests.get('http://www.neuedu.com') print(resp) # # 也可以这么写 response = requests.request("get", "http://www.neuedu.com") print(response) #

response.text 和response.content的区别 (二)Requests
文章图片
import requests url = 'http://www.baidu.com/' r = requests.get(url)

# 查看响应内容 str类型 #r.text

r.encoding

'ISO-8859-1'

# 手动修改相应编码格式 r.encoding = 'utf-8' r.encoding

'utf-8'

# 直接把相应数据改成utf-8 # r.content.decode()

# 获取响应头 r.headers

{'Accept-Ranges': 'bytes', 'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform', 'Content-Length': '2381', 'Content-Type': 'text/html', 'Date': 'Mon, 17 Jun 2019 15:13:04 GMT', 'Etag': '"588604c4-94d"', 'Last-Modified': 'Mon, 23 Jan 2017 13:27:32 GMT', 'Pragma': 'no-cache', 'Server': 'ATS/8.0.3', 'Set-Cookie': 'BDORZ=27315; max-age=86400; domain=.baidu.com; path=/', 'Age': '0', 'Connection': 'keep-alive'}

添加 headers 和 查询参数
为什么请求需要带上header?
模拟浏览器,欺骗服务器,获取和浏览器一致的内容
headers的形式:字典
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} # 用法: requests.get(url,headers=headers)

发送带参数的请求 什么叫做请求参数:
列1: http://www.webkaka.com/tutorial/server/2015/021013/ 不是
例2: https://www.baidu.com/s?wd=python&c=b 是
import requestskw = {'wd':'东软'}headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}# params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode() response = requests.get("http://www.baidu.com/s?", params=kw, headers = headers)# 查看响应内容,response.text 返回的是Unicode格式的数据 print(response.text)

# 查看响应内容,response.content返回的字节流数据 print(response.content)# 查看完整url地址 print(response.url)# 查看响应头部字符编码 print(response.encoding)# 查看响应码 print(response.status_code)

没有添加请求头的知乎网站
import requests url = 'https://www.zhihu.com' headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}

r = requests.get(url) r.status_code

400

r = requests.get(url,headers= headers) r.status_code

200

案例:百度贴吧的爬取
  • 获取指定页数
  • 将贴吧保存成文件
    参考代码:
import requests""" 目标: 爬取百度贴吧页面: 1、构造url 2、构造请求头 3、发送请求 4、保存数据""" class Baidu(object):def __init__(self,name,pn): # 保存传入的贴吧名称 self.name = name self.url = 'https://tieba.baidu.com/f?kw={}&ie=utf-8&pn='.format(name) self.headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } # 构造url列表,拼接的页数 self.url_list = [self.url + str(pn*50) for pn in range(pn)] print(self.url_list)# 发送请求获取数据,需要修改传入的url def get_data(self,url): response = requests.get(url,headers=self.headers) return response.content# 保存数据 def save_data(self,data,num): # 构造保存数据的文件名称 file_name = self.name + '_' + str(num) + '.html' with open(file_name,'wb') as f: f.write(data)# 执行方法 def run(self): # 遍历url列表 for url in self.url_list: # print (url) # 调用发送请求的方法,获取数据 data = https://www.it610.com/article/self.get_data(url) # 获取self.url_list索引值 num = self.url_list.index(url) # 调用保存数据的方法 self.save_data(data,num) import sysif __name__ =='__main__': # 传入参数,贴吧名称,页数 name = sys.argv[1] pn = int(sys.argv[2]) # print(type(name)) # print(type(pn)) # print(name,pn) baidu = Baidu(name,pn) baidu.run()

在终端运行如下命令:
python3 spider_tieba.py 李毅 3

本地会生成3个html文件哦

(二)Requests
文章图片
Requests高阶(POST) 发送POST请求
哪些地方我们会用到POST请求:
  • 登录注册( POST 比 GET 更安全)绝大多数的登录会使用post请求,极少数网站仍然在使用get请求进行登录
  • 向服务器传输的数据量比较多的时候,或者向服务器传输大文件
  • 所以同样的,我们的爬虫也需要在这两个地方回去模拟浏览器发送post请求
用法:
response = requests.post(url, data = https://www.it610.com/article/data, headers=headers) # data 的形式:字典

案例:访问金山词霸在线翻译,获取翻译结果
网址:http://fy.iciba.com/
需求
1、构造url
2、请求头
3、构造请求体
4、发送请求,输出数据
如下如是浏览器的演示效果,接下来我们要用python代买去实现这一功能

(二)Requests
文章图片

注释:
  • 1.XHR:筛选使用Ajax请求的network(ajax技术的核心是XMLHttpRequest对象(简称XHR),这是由微软首先引入的一个特性,其他浏览器提供商后来都提供了相同的实现。XHR为向服务器发送请求和解析服务器响应提供了流畅的接口,能够以异步方式从服务器取得更多信息,意味着用户单击后,可以不必刷新页面也能取得新数据)
  • 2.当左侧输入框发生 变化就会触发Ajax请求事件
    1. Form Data就是post请求的表单数据
      参考代码:
import requests import jsonclass JinShan(object):def __init__(self,word): self.url = 'http://fy.iciba.com/ajax.php?a=fy' self.headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } # 构造请求的参数 self.post_data = https://www.it610.com/article/{"f": "auto", "t": "auto", "w": word } # 发送请求 def request_post(self): response = requests.post(url=self.url,headers=self.headers,data=https://www.it610.com/article/self.post_data) # print(response.content.decode()) return response.content.decode()# 解析数据 def parse_data(self,data): # 把响应数据转成字典 dict_data = json.loads(data) # 判断out键是否存在,不能判断一个字符串是否在字典的索引 # if'out' in data: #content = (dict_data['content']['out']) # else: #content = (dict_data['content']['word_mean'][0]) # 进行异常处理 try: content = (dict_data['content']['out']) except: content = (dict_data['content']['word_mean'][0]) print (content)def run(self): # 调用发送请求,并获取数据 data = https://www.it610.com/article/self.request_post() # 调用解析数据方法 self.parse_data(data)if __name__ =='__main__': import sys word = sys.argv[1] jinshan = JinShan(word) jinshan.run()

在终端运行命令之后会有下面的效果

(二)Requests
文章图片
使用IP代理爬虫 IP代理既代理服务器,其功能主要就是代理网络用户去获取网络信息,形象的说就是网络信息的中转站
为什么爬虫需要使用代理?
  • 让目标服务器以为不是同一个客户端在请求,放置因为ip发送请求过多而被反爬
  • 防止我们的真实地址被泄露,防止被追究

    (二)Requests
    文章图片
代理分类
(二)Requests
文章图片

使用免费代理网站,比如快代理 https://www.kuaidaili.com/free/找到免费的ip
(二)Requests
文章图片

下面是使用代理的示例代码:
import requests# 使用代理 url = 'http://www.baidu.com/'# 免费代理 proxies = { 'http':'http://115.210.24.183:9000', 'https':'https://183.129.207.86:14002' } # # 付费代理,用户名:密码@ip和port # proxies = { #'http':'http://user:pwd@115.223.200.85:9000' # }response = requests.get(url,proxies=proxies) print(response.text)

cookie和session 本质上都是基于键值对的字符串
两者区别:
  • cookie数据存放在客户的浏览器上,session数据放在服务器上
  • cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗(使用用户的cookies获取相关信息
  • session会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能
  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
利弊:
  • 带上cookie、session的好处:很多网站必须登录之后(或者获取某种权限之后)才能能够请求到相关数据
  • 带上cookie、session的弊端:一套cookie和session往往和一个用户对应.请求太快,请求次数太多,容易被服务器识别为爬虫。从而是账号收到损害
  • 使用建议
    1.不需要cookie的时候尽量不去使用cookie
    2.为了获取登录之后的页面,我们必须发送带有cookies的请求,此时为了确保账号安全应该尽量降低数据采集速度
案例:使用cookies来获取登录之后人人网的响应
首先浏览器登录人人网,然后打开调试模式,复制url和cookie

(二)Requests
文章图片

参考代码如下:
import requests import re """ 使用cookie进行模拟登录 1、首先使用浏览器登录网站 2、获取cookie信息 3、保存cookie信息放到请求头中""" # 登录后用户信息页 url = 'http://www.renren.com/971209342'# 保存cookie信息 headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", "Cookie": "anonymid=jx19bd0l-4r5q5y; JSESSIONID=abcsD77Gb0el7fJktQOTw; depovince=GW; _r01_=1; ick_login=19787144-5838-490f-b599-34a22b58aa7c; t=06700184d453813c5b594f40b29cd9412; societyguester=06700184d453813c5b594f40b29cd9412; id=971209342; xnsid=974c659d; jebecookies=7b441396-b2be-4c75-ac03-4466a9fc763f|||||; ver=7.0; loginfrom=null" }# 发送请 response = requests.get(url, headers=headers)# 获取响应,并且解码成str,使用正则获取响应中的字符串 print(re.findall('关注内容', response.content.decode())) print(response.status_code)

输出结果如下:
['关注内容'] 200

Cookies 和 session
如果一个响应中包含了cookie,那么我们可以利用 cookies参数拿到
import requestsurl = 'http://www.baidu.com' headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" }# 设置请求的超时时间,单位是s # response = requests.get(url,timeout=3)response = requests.get(url, headers=headers) # 获取cookie信息 print(response.cookies)# 把cookie转成字典 content = requests.utils.dict_from_cookiejar(response.cookies) print(content) # 将cookie字典转成对象 c = requests.utils.cookiejar_from_dict(content) print(c)

运行结果:
, , , ]> {'H_PS_PSSID': '1443_21123_29135_29237_29098_29369_28832_29220_26350', 'delPer': '0', 'BDSVRTM': '0', 'BD_HOME': '0'} , , , ]>

使用session实现人人网登录 在 requests 里,session对象是一个非常常用的对象,这个对象代表一次用户会话:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开。
【(二)Requests】会话能让我们在跨请求时候保持某些参数,比如在同一个 Session 实例发出的所有请求之间保持 cookie
import requests import reurl = 'http://www.renren.com/PLogin.do'# 保存cookie信息 headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", }# 构造session回话对象 session = requests.session()# 构造post请求data数据 data = https://www.it610.com/article/{'email':'1900000000', 'password':'neuedu' } # 发送post请求 session.post(url,headers=headers,data=https://www.it610.com/article/data)# 验证登录是否成功 response = session.get('http://www.renren.com/963112933')##打印响应内容 print(response.text)

    推荐阅读