【python爬虫 系列】4.Requests数据抓取

第四节:Requests数据抓取
4.1.Requests简介与安装
Requests是python的一个HTTP客户端库,几乎可以解决我们遇到的任何爬虫问题,其强大简洁的API足以让人体会到python的优雅。
作为最强大的python非官方请求库,它能解决90%的爬虫问题

Windows下安装通过pip install requests
Mac下安装通过pip3 install requests

不行的话利用清华镜像:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests_

#注:之后就不一一赘述模块安装方法,安装模块除了特殊的都是这个方法,
今后所言只会说pip install 模块名

要使用requests,首先推荐阅读requests的官方文档

https://2.python-requests.org//zh_CN/latest/user/quickstart.html

基本用法代码:

import requests

def get_html(url):                             #一个功能写一个函数 
	html = requests.get(url)     #设置get()请求页面
	if html.status_code == 200:  #判断response返回正常
		html.encoding = "utf8"   #设置文本解码方式
		print(html.text)
	else:
		print("get error"+html.url)

if __name__ == "__main__":        
 #当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。
	url = "https://baidu.com"
	get_html(url)

HTTP请求中我们通常只会用GET和POST,requests对于区分了两种不同的请求方式。分别是带参数和不带参数,下边给出实例:
#不带参数
https://www.baidu.com
#带参数
https://www.baidu.com/s?wd=python
判断URL是否带有参数,可以通过对符号?的判断。一般网站URL后边带有?说明带有参数,参数的规则如下
1)?后接参数
2)参数之间用&连接
Requests实现GET请求,对可带参数的URL有两种方式:

import requests
#方法一
html1 = requests.get("https://www.baidu.com/s?wd=python")
#方法二
url = "https://www.baidu.com/s"
paramas = {"wd":'python'}
html2 = requests.get(url,paramas)
print(html1,html2)

两种方法都可以,实际开发中建议第二种,
因为更加简洁优雅,体现了python的语法。
其有如下优点:

方便传输参数
方便维护
方便调试
耦合性低,模块化

POST方法就是我们日常生活中提交表单的方法,比如登录验证之类的。Requests实现的POST需要传递参数data,可以使字典或者json结构,或者元组,列表等。

#提交post
import requests
#字典
data1 = {"name":"python","password":233}
#json
import json
data2 = {"name":'python',"password":233}
data2 = json.dumps(data2)
html = requests.post("https://www.baidu.com",data=data2)
print(html.text)

需要注意的是,
GET请求传递的是params,POST传递的是data,不能混淆二者。

import requests

def post_html(url):
	data = {"name":"python","passord":223}
	html = requests.post(url,data=data)    #post通常用于请求表单 注意其传递的参数是data
	if html.status_code == 200:
		html.encoding = "utf8"
		print(html.text)
	else:
		print("get error"+html.url)


if __name__=="__main__":
	url = "http://baidu.com"
	post_html(url)

此外,服务器返回的信息里包含了许多我们需要的数据,比如

Html.status_code	相应状态码
Html.raw	      原始响应体
Html.content	字节响应体,需要解码
Html.text	字符串的响应方式
Html.headers	服务器响应头
Html.josn()	requests内置的json解码器
Html.cookies	获取请求后的cookies
Html.encoding	获取编码格式

4.2.构建复杂请求
复杂的请求方式包括请求头,代理,证书验证和cookies验证。Requests对此做了简化,将这些功能封装在了requests参数中。
1)session
维持会话:
正常我们浏览器访问页面时,网站会知道这是一系列的操作,
也就是互通的,

而程序访问是单个独立的,服务器认为是两个不同的人访问的。
这样就会出现许多的样板代码,就类似于每次get都需要加headers

这个时候就引入了我们的session,它的好处如下:

  1. 维持会话
  2. 自动保存cookies
  3. 传递参数,Session会自动传递参数,保存cookies和headers
    书写方式: 先写入程序:
    session=requests.session()
    session.headers=headers
    再将程序中requests替换为session,并去除headers等

复杂的请求方式包括请求头,代理,证书验证和cookies验证。Requests对此做了简化,将这些功能封装在了requests参数中。
2) 添加请求头:请求头是字典格式
请求头可以从浏览器的 requests headers处获取
在这里插入图片描述
书写:

headers = {'Referer': 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E7%83%AD%E6%90%9C&oq=%E7%83%AD%E6%90%9C&rsp=-1',
			'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3947.100 Safari/537.36',
			'X-Requested-With': 'XMLHttpRequest'}

2) 使用IP代理(NAT)(访问国外网站的时候使用)
必须是两部分,一是http,二是https,一般加上timeout,以防代理失效
可以利用快代理,西刺代理,都是免费的(但不一定好用)
**

#ip代理
import requests
proxies={
		'http':'112.84.72.7',
		"https":"112.84.72.7"
}
html = requests.get("http://www.youtube.com/",proxies=proxies,timeout=10)
print(html.status_code)

**
3) https证书验证:
通常是用来关闭的,默认是True
如果需要设置证书文件,则需要传递证书路径
出现下面情况时候使用(ssl error 之类):

在这里插入图片描述

import requests
ur1='https://baidu.com '
#关闭证书验证
html1=requests.get(ur1,verify=False)
print(html1.status_code)
#设置证书路径
htm12=requests.get (ur1,verify='D:/path/ mycert')

4) 超时设置
有时候因为各种因素,我们请求一个网站,在得到响应之前,会等待一段时间。如果不想让程序等待那么长时间,可以自己设置一个等待时间,超时的话会引发一个异常。

5) 使用cookies
cookies是用来识别用户的,在requests中以字典形式存在。获取方式主要是通过服务器的设置,我们也可以自己伪造。

#使用cookies
import requests
#这是一段取自百度的cookies
cookies='FG=1; pgv_ pvi=5209723904'
cookies_dict=dict()
for i in cookies.split(';'):
	value=i.split("=")
	cookies_dict[value[0]]=value[1] 
html=requests. get('https://www.baidu.com',cookies=cookies_dict)
print(html.status_code)

以上是我们自己传递cookies,那么如何获取服务器的cookies呢?第一种办法是打开浏览器的开发者工具,在network里边寻找(和上述请求头操作一样);第二种方法是通过requests获取
4.3上传与下载
下载文件就是从服务器请求文件,然后保存在本地,以下载图片为例,代码如下:
文件下载本身得到的内容是字节流,以字节方式写入才能实现下载。
基本代码(可封装为一个模块使用)

def download(url):
	img = requests.get(url,headers=headers)
	with open("imgs/{}.jpg".format(uuid.uuid4()),"wb") as f:  #注意后缀格式  填写随意的名称
		chunks = img.iter_content(125)        #减少cpu压力,一次读取一部分
		for c in chunks:
			f.write(c)

文件的上传更为复杂一些,是将本地的文件以字节流形式上传到服务器,由服务器接收后做出相应。
基本代码:

#上传文件
import requests

files = {"file":#固定的文件名
			("render",open("render.html","rb"), #文件名+文件
			"application/html",                 #文件格式 可以更改如txt等
			{"Expires":'0'})}                   #额外的添加的参数 这里是过期时间
def post_html(url):
	html = requests.post(url,files=files)
	if html.status_code==200:
		print("get error:"+html.url)

if __name__=="__main__":
	url ="https://www.csdn.net/"
	post_html(url)

4.4.urllib常用参数补充
具体参见https://docs.python.org/zh-cn/3/library/urllib.parse.html#module-urllib.parse
from urllib import parse

Urllib.parse.urlparse: 分解URL(含有解析)
Urllib.parse.urljoin: 将两个URL结合在一起
Urllib.parse.quote: 对字符串转义
Urllib.parse.urlsplit: 分割URL

1.Urllib.parse.urljoin

from urllib import parse
url1 = 'https://bilbil/com/'
url2 = '/img_1'
url = url1 + url2
print("no urllib:"+url)
url = parse.urljoin(url1,url2)
print("urllib:"+url)
输出:
no urllib:https://bilbil/com//img_1(非法url)
urllib:https://bilbil/img_1(合法url)

从上述我们可以看出,urljoin的重要性
2. Urllib.parse.quote

text='%2BKMrOEYbFdQHjteHui6ljLQIHr68g&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=12&rsv_sug1=9&rsv_sug7=100&rsv_sug2=0&inputT=2311&rsv_sug4=5300'
print(parse.unquote(text))  #翻译为我们看的语言
#print(unquote())           #翻译为机器的语言

3. Urllib.parse.urlsplit,Urllib.parse.urlparse

url = 'https://www.baidu.com/s?tn=25017023_6_dg&ch=1&ie=UTF-8&wd=http%3A%2F%2Fhttpbin.org%2Fpost'
print(parse.urlsplit(url))  #分割
print(parse.urlparse(url))  #分析 高级一点

结果:

SplitResult(scheme='https', netloc='www.baidu.com', path='/s', query='tn=25017023_6_dg&ch=1&ie=UTF-8&wd=http%3A%2F%2Fhttpbin.org%2Fpost', fragment='')
ParseResult(scheme='https', netloc='www.baidu.com', path='/s', params='', query='tn=25017023_6_dg&ch=1&ie=UTF-8&wd=http%3A%2F%2Fhttpbin.org%2Fpost', fragment='')
可以看到parse.urlparse是更高级一点的

4.5.利用requests下载图片,音视频
通过上述的介绍,我们初步了解了requests的使用,那么如何利用request获取图片,音视频呢,我们就以获取百度图片的代码作为说明,一个利用session,另一个没有利用,可以作为参考。

#下载图片/视频等 无session
import requests
import json
import uuid
'''https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=30&rn=30&gsm=1e&1582460979488=
https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=60&rn=30&gsm=3c&1582460979640=
https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=90&rn=30&gsm=5a&1582460980025='''

headers = {'Referer': 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E7%83%AD%E6%90%9C&oq=%E7%83%AD%E6%90%9C&rsp=-1',
			'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3947.100 Safari/537.36',
			'X-Requested-With': 'XMLHttpRequest'}

#图片视频url下载 都是二进制
def download(url):
	img = requests.get(url,headers=headers)
	with open("imgs/{}.jpg".format(uuid.uuid4()),"wb") as f:  #注意后缀格式  填写随意的名称
		chunks = img.iter_content(125)        #减少cpu压力,一次读取一部分
		for c in chunks:
			f.write(c)

def get_html(url):
	html = requests.get(url,headers=headers)
	try:                                        #并不是所有的都能输出为json
		#print(html.json()["data"])
		#result = html.json()['data']           #方法一:requests自带简单json
		result = json.loads(html.text)["data"]  #方法二:python json
		for r in result:
			if r:                               #判断非空才输出
				print(r["thumbURL"])
				download(r["thumbURL"])
	except Exception as e:
		print(e)

url = ['https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn={}&rn=30&gsm=1e&1582460979488='.format(i) for i in range(30,100,30)]


if __name__=="__main__":
	for u in url:
		get_html(u)


#利用session
import requests
import json
import uuid
'''https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=30&rn=30&gsm=1e&1582460979488=
https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=60&rn=30&gsm=3c&1582460979640=
https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=90&rn=30&gsm=5a&1582460980025='''

headers = {'Referer': 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E7%83%AD%E6%90%9C&oq=%E7%83%AD%E6%90%9C&rsp=-1',
			'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3947.100 Safari/537.36',
			'X-Requested-With': 'XMLHttpRequest'}

session=requests.session()
session.headers=headers

#图片视频url下载 都是二进制
def download(url):
	img = session.get(url)
	with open("imgs/{}.jpg".format(uuid.uuid4()),"wb") as f:  #注意后缀格式  填写随意的名称
		chunks = img.iter_content(125)        #减少cpu压力,一次读取一部分
		for c in chunks:
			f.write(c)

def get_html(url):
	html = session.get(url)
	try:                                        #并不是所有的都能输出为json
		#print(html.json()["data"])
		#result = html.json()['data']           #方法一:requests自带简单json
		result = json.loads(html.text)["data"]  #方法二:python json
		for r in result:
			if r:                               #判断非空才输出
				print(r["thumbURL"])
				download(r["thumbURL"])
	except Exception as e:
		print(e)

url = ['https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E7%83%AD%E6%90%9C&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word=%E7%83%AD%E6%90%9C&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn={}&rn=30&gsm=1e&1582460979488='.format(i) for i in range(30,100,30)]


if __name__=="__main__":
	for u in url:
		get_html(u)

4.6. 拓展模块
requests_html 和request都是一个作者开发的,
我们可以利用requests_html写一个异步爬虫,因为它支持原生异步爬虫
也可以执行js,帮助我们破解js加密

值得注意的是它仅支持python3.6.0版本

安装模块:pip install requests_html

from requests_html import AsyncHTMLSession
import time

#异步是单线程,伪装为多并发
session=AsyncHTMLSession() #异步session
#async标志这是一个异步爬虫函数
#await是等待结果返回
async def get_html():
	html = await session.get("https://www.csdn.net/")
	return html.status_code

if __name__ == "__main__":
	s = time.time()
	tasks = [get_html for i in range(100)]
	session.run(*tasks)
	print(time.time()-s)

运行获取时间的话,我们会发现异步爬虫的速度很快,几乎快于常规的几倍

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值