1 使用requests处理cookie请求的三种方法
1.1回顾cookie和session的区别
- cookie数据存放在客户的浏览器上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
1.2 爬虫中为什么要使用cookie
- 带上cookie的好处
- 能够访问登录后的页面
- 正常的浏览器在请求服务器的时候肯定会带上cookie(第一次请求某个地址除外),所以对方服务器有可能会通过是否携带cookie来判断我们是否是一个爬虫,对应的能够起到一定的反爬的效果
- 带上cookie的坏处
- 一套cookie往往对应的是一个用户的信息,请求太频繁有更大的可能性被对方识别为爬虫
- 那么上面的问题如何解决 ?使用多个账号
1.3 使用 session
session = requests.Session()
session.post(url,data) #cookie会存在session中
session.get(url) #会带上之前的cookie
-
requests 提供了一个叫做session类,来实现客户端和服务端的
会话保持
-
会话保持有两个内涵:
- 保存cookie
- 实现和服务端的长连接
-
使用方法
session = requests.session() response = session.get(url,headers) - 1 实例化对象 - 2 session.get(url) #cookie保存在session中 - 3 session.get(url) #带上保存在session中cookie
session实例在请求了一个网站后,对方服务器设置在本地的cookie会保存在session中,下一次再使用session请求对方服务器的时候,会带上前一次的cookie
-
动手:
动手尝试使用session来登录人人网:
http://www.renren.com/PLogin.do
(先不考虑这个url地址从何而来),请求体的格式:{"email":"username", "password":"password"}
1.4 cookie放在headers中
了解headers中cookie
- headers中的cookie:
- 使用分号(;)隔开
- 分号两边的类似a=b形式的表示一条cookie
- a=b中,a表示键(name),b表示值(value)
- 在headers中仅仅使用了cookie的name和value
由于headers中对cookie仅仅使用它的name和value,所以在代码中我们仅仅需要cookie的name和value即可
在headers中使用cookie
headers = {
"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Cookie":" Pycharm-26c2d973=dbb9b300-2483-478f-9f5a-16ca4580177e; Hm_lvt_98b9d8c2fd6608d564bf2ac2ae642948=1512607763; Pycharm-26c2d974=f645329f-338e-486c-82c2-29e2a0205c74; _xsrf=2|d1a3d8ea|c5b07851cbce048bd5453846445de19d|1522379036"}
requests.get(url,headers=headers)
cookie有过期时间,所以直接复制浏览器中的cookie可能意味着下一程序继续运行的时候需要替换代码中的cookie,对应的我们也可以通过一个程序专门来获取cookie供其他程序使用;当然也有很多网站的cookie过期时间很长,这种情况下,直接复制cookie来使用更加简单
1.3 使用cookies参数
- cookies的形式:字典
cookies = {"cookie的name":"cookie的value"}
- 使用方法:
requests.get(url,headers=headers,cookies=cookie_dict)
2. requests模块获取cookie
requests.utils.dict_from_cookiejar : 把cookiejar对象转化为字典
import requests
url = "http://www.baidu.com"
response = requests.get(url)
print(type(response.cookies))
cookies = requests.utils.dict_from_cookiejar(response.cookies)
print(cookies)
输出为:
<class 'requests.cookies.RequestsCookieJar'>
{'BDORZ': '27315'}
寻找登录接口的方法
- form表单action对应的url地址
- 用户名和密码的input标签中,name的值作为键,用户名和密码作为值的字典,作为post data
- 通过抓包,定位url地址
- form data
3. requests处理证书错误
出现这个问题的原因是:ssl的证书不安全导致
在代码中请求如下:
import requests
url = "https://www.12306.cn/mormhweb/"
response = requests.get(url)
返回
ssl.CertificateError ...
为了在代码中能够正常的请求,我们修改添加一个参数
import requests
url = "https://www.12306.cn/mormhweb/"
response = requests.get(url,verify=False)
4. 超时参数的使用
在平时网上冲浪的过程中,我们经常会遇到网络波动,这个时候,一个请求等了很久可能任然没有结果
对应的,在爬虫中,一个请求很久没有结果,就会让整个项目的效率变得非常低,这个时候我们就需要对请求进行强制要求,让他必须在特定的时间内返回结果,否则就报错
使用方法如下:
response = requests.get(url,timeout=3)
通过添加timeout参数,能够保证在3秒钟内返回响应,否则会报错
这个方法还能够拿来检测代理ip的质量,如果一个代理ip在很长时间没有响应,那么添加超时之后也会报错,对应的这个ip就可以从代理ip池中删除
5. retrying模块的使用
上述方法能够加快我们整体的请求速度,但是在正常的网页浏览过成功,如果发生速度很慢的情况,我们会做的选择是刷新页面,那么在代码中,我们是否也可以刷新请求呢? 对应的,retrying模块就可以帮助我们解决
- retrying模块的地址:https://pypi.org/project/retrying/
- retrying 模块的使用
- 使用retrying模块提供的retry模块 : pip install retrying
- 通过装饰器的方式使用,让被装饰的函数反复执行
- retry中可以传入参数
stop_max_attempt_number
,让函数报错后继续重新执行,达到最大执行次数的上限,如果每次都报错,整个函数报错,如果中间有一个成功,程序继续往后执行
所以我们可以结合前面的知识点和retrying模块,把我们需要反复使用的请求方法做一个简单的封装,在后续任何其他地方需要使用的时候,调用该方法就行
代码参考
# parse.py
import requests
from retrying import retry
headers = {}
@retry(stop_max_attempt_number=3) #最大重试3次,3次全部报错,才会报错
def _parse_url(url)
response = requests.get(url, headers=headers, timeout=3) #超时的时候回报错并重试
assert response.status_code == 200 #状态码不是200,也会报错并充实
return response
def parse_url(url)
try: #进行异常捕获
response = _parse_url(url)
except Exception as e:
print(e)
response = None
return response
6. 爬虫中数据的分类
- 结构化数据:json,xml等
- 处理方式:直接转化为python类型
- 非结构化数据:HTML
- 处理方式:正则表达式、xpath
7. 数据提取之json
1. json和python数据格式区别
json | python |
---|---|
object | dict |
array | list |
string | unicode |
number(int) | int,long |
number(real) | float |
true | True |
false | False |
null | None |
2. json数据格式的转换
json字符串 --> json.loads(json_str) --> 字典
字典 --> json.dumps(json_dict) --> json字符串
包含json的类文件对象 --> json.load() --> python数据类型
python数据类型 --> json.dump(dict, fp) --> 包含json的类文件数据
其中类文件对象的理解:
具有read()或者write()方法的对象就是类文件对象,比如f = open(“a.txt”,”r”) f就是类文件对象
具体使用方法:
#json.dumps 实现python类型转化为json字符串
#indent实现换行和空格
#ensure_ascii=False实现让中文写入的时候保持为中文
json_str = json.dumps(mydict,indent=2,ensure_ascii=False)
#json.loads 实现json字符串转化为python类型
my_dict = json.loads(json_str)
#json.dump 实现把python类型写入类文件对象
with open("temp.txt","w") as f:
json.dump(mydict,f,ensure_ascii=False,indent=2)
# json.load 实现类文件对象中的json字符串转化为python类型
with open("temp.txt","r") as f:
my_dict = json.load(f)
8.三元运算符
if 条件成立,if前面的结果赋值给to,否则else后面的内容赋值给to
to = "en" if lan=="zh" else "zh"
9.字典推导式
In [8]: {i:i+10 for i in range(10)}
Out[8]: {0: 10, 1: 11, 2: 12, 3: 13, 4: 14, 5: 15, 6: 16, 7: 17, 8: 18, 9: 19}
In [9]: {i:i+10 for i in range(10) if i%2==0}
Out[9]: {0: 10, 2: 12, 4: 14, 6: 16, 8: 18}
10.练习代码
1. 百度翻译判断语言类型
import requests
import json
class Fanyi:
def __init__(self,query_string):
self.query_string = query_string
self.url = "https://fanyi.baidu.com/basetrans"
self.headers = {"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"}
self.langdetect_url = "https://fanyi.baidu.com/langdetect"
def get_post_data(self):
#判断需要翻译的语言类型
# url
data = {"query":self.query_string}
# 发起请求 获取响应
json_str = self.parse_url(self.langdetect_url,data)
# 提取数据
lan = json.loads(json_str)["lan"]
to = "en" if lan=="zh" else "zh"
post_data = {
"query": self.query_string,
"from": lan,
"to": to,
}
return post_data
def parse_url(self,url,post_data):
response = requests.post(url=url,data=post_data,headers=self.headers)
return response.content.decode()
def get_ret(self,json_str):
json_dict = json.loads(json_str)
ret = json_dict["trans"][0]["dst"]
print("{} 的翻译是: {}".format(self.query_string, ret))
def run(self):
# url
post_data = self.get_post_data()
# 发送请求 获取响应
json_str = self.parse_url(self.url,post_data)
# 提取数据
self.get_ret(json_str)
if __name__ == '__main__':
query_string = "hello"
fanyi = Fanyi(query_string)
fanyi.run()
2. 携带cookie登录人人
列表推导式的使用、字符串的切割、
cookie_dict = {i.split("=")[0]:i.split("=")[1] for i in cookie.split(";")}
import requests
# cookie使用方式一:
# url = "http://www.renren.com/969422209/profile"
# headers = {
# "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
# "Cookie":"anonymid=jqssugyx-z9kad7; depovince=JS; _r01_=1; JSESSIONID=abc3XQzWlaYMdhhV5S-Gw; ick_login=8f5b4e7f-950e-440a-a991-91f34253e3c6; jebe_key=967800f0-ab5e-4efe-b280-aebffd675ac8%7Ca3aa3372b122c1c97f519233b0fde327%7C1547256984705%7C1%7C1547256985274; _ga=GA1.2.1363047991.1547257026; _gid=GA1.2.305736515.1547257026; ick=7abb18fb-c8a7-4d49-912b-977556a644dd; first_login_flag=1; ln_uact=13390611285; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; wp_fold=0; wp=0; jebecookies=b248b52d-893d-41a5-b568-4f615c3b93b9|||||; _de=58E7D23B141293BCDC76A31CB46C072E; p=0e80f7d41d985d522080f7f2eb3132c29; t=a2df81d0b9027fe188b243fdf9f0bf949; societyguester=a2df81d0b9027fe188b243fdf9f0bf949; id=969422209; xnsid=c011459e; ver=7.0; loginfrom=null; jebe_key=967800f0-ab5e-4efe-b280-aebffd675ac8%7C17a6b28d4f5feaa26042443b3f1909db%7C1547260840167%7C1%7C1547260840763"
# }
# response = requests.get(url,headers=headers)
# with open('renren.html','w',encoding='utf-8')as f:
# f.write(response.content.decode())
# cookie使用方式二
url = "http://www.renren.com/969422209/profile"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
}
cookie = "anonymid=jqssugyx-z9kad7; depovince=JS; _r01_=1; JSESSIONID=abc3XQzWlaYMdhhV5S-Gw; ick_login=8f5b4e7f-950e-440a-a991-91f34253e3c6; jebe_key=967800f0-ab5e-4efe-b280-aebffd675ac8%7Ca3aa3372b122c1c97f519233b0fde327%7C1547256984705%7C1%7C1547256985274; _ga=GA1.2.1363047991.1547257026; _gid=GA1.2.305736515.1547257026; ick=7abb18fb-c8a7-4d49-912b-977556a644dd; first_login_flag=1; ln_uact=13390611285; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; wp_fold=0; wp=0; jebecookies=b248b52d-893d-41a5-b568-4f615c3b93b9|||||; _de=58E7D23B141293BCDC76A31CB46C072E; p=0e80f7d41d985d522080f7f2eb3132c29; t=a2df81d0b9027fe188b243fdf9f0bf949; societyguester=a2df81d0b9027fe188b243fdf9f0bf949; id=969422209; xnsid=c011459e; ver=7.0; loginfrom=null; jebe_key=967800f0-ab5e-4efe-b280-aebffd675ac8%7C17a6b28d4f5feaa26042443b3f1909db%7C1547260840167%7C1%7C1547260840763"
cookie_dict = {i.split("=")[0]:i.split("=")[1] for i in cookie.split(";")}
response = requests.get(url,headers=headers,cookies=cookie_dict)
with open('renren2.html','w',encoding='utf-8')as f:
f.write(response.content.decode())
3. requests获取cookie
import requests
url = "http://www.baidu.com"
response = requests.get(url)
print(type(response.cookies))
cookies = requests.utils.dict_from_cookiejar(response.cookies)
print(cookies)
4. 获取json数据
import json
import requests
from pprint import pprint #美化打印
url = "https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items?&start=0&count=18&loc_id=108288&_=1547298724078"
headers = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
"Referer":"https://m.douban.com/movie/nowintheater?loc_id=108288"
}
response = requests.get(url,headers=headers)
# print(response.content.decode())
# json.loads 字符串转字典
json_str = response.content.decode()
ret1 = json.loads(json_str)
# pprint(ret1)
# print(type(ret1))
# json.dumps 字典转字符串
# with open("a.txt","w",encoding='utf-8') as f:
# f.write(json.dumps(ret1,ensure_ascii=False,indent=4)) #写入的时候需要字典转字符串
# with open("a.txt","r",encoding='utf-8')as f:
# # f.write(json.load(ret1))
# ret2 = json.load(f)
# print(type(ret2))
# print(ret2)
with open("b.txt",'w',encoding='utf-8')as f:
json.dump(ret1,f,ensure_ascii=False,indent=2)