文章目录
一、urllib模块
1.什么是urllib模块?
python的内置网络请求模块
为什么要学习这个模块?
1,有些比较老的爬虫项目用的就是这个技术
2.有的时候我们去爬取一些数据需要请求和urllib的配合使用
3.内置模块是标准库
示例1
# 保存'未来汽车'图片到本地
import requests
response = requests.get(
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fphotocdn.sohu.com%2F20120823%2FImg351337268.jpg&refer=http%3A%2F%2Fphotocdn.sohu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1621479722&t=5cda4533dad4056d5809bf5f2450a22f').content
with open('未来汽车.jpg', 'wb') as f:
f.write(response)
示例2
# 保存'未来汽车'图片到本地
from urllib.request import urlretrieve
response = urlretrieve(
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fphotocdn.sohu.com%2F20120823%2FImg351337268.jpg&refer=http%3A%2F%2Fphotocdn.sohu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1621479722&t=5cda4533dad4056d5809bf5f2450a22f',
'未来汽车.jpg')
1.urllib.request模块
python2:urllib2,urllib
python3:把urllib和urllib2合并常用的方法
- urllib.request.urlopen(“网址”) 作用 :向网站发起一个请求并获取响应
- 字节流 = response.read()
- 字符串 = response.read().decode(“utf-8”)
- urllib.request.Request"网址",headers=“字典”) urlopen()不支持重构User-Agent
示例1
# urllib.request实现
# urllib.request.urlopen('网址')
# 作用:向网站发起请求并响应
import urllib.request
response = urllib.request.urlopen('https://www.baidu.com/')
print(type(response)) # <class 'http.client.HTTPResponse'>
print(response.read())
'''
b'<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace("https://","http://"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>\r\n</body>\r\n</html>'
''' # 1.字节流bytes,需要解码 2.数据不对(网站做了反爬),需要添加ua
示例2
# 示例2
import urllib.request
headers = {'User-Agent': 'Mozilla/5.0'}
req = urllib.request.Request("https://www.baidu.com/",headers=headers)
response = urllib.request.urlopen(req)
print(response.read().decode('utf-8'))
# 这样出来的数据没有问题
2.响应对象
- read() 读取服务器响应的内容
- getcode() 返回HTTP的响应码
- geturl() 返回实际数据的URL(防止重定向问题)
示例
import urllib.request
# 向指定的url地址发起请求,并返回服务器响应的数据(文件的对象)
url = "http://www.baidu.com"
# 编码
newUrl2 = urllib.request.quote(url)
print(newUrl2) # http%3A//www.baidu.com
# 解码
newUrl1 = urllib.request.unquote(newUrl2)
print(newUrl1) # http://www.baidu.com
response = urllib.request.urlopen(newUrl1)
data = response.read()
print(data)
'''
b'<!DOCTYPE html><!--STATUS OK-->\n\n\n <html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color" content="#2932e1"><meta name="description" content="\xe5\x85\xa8\xe7\x90\x83\xe6\x9c\x80\xe5\xa4\xa7\xe7\x9a\x84\xe4\xb8\xad\xe6\x96\x87\xe6\x90\x9c\xe7\xb4\xa2\xe5\xbc\x95\xe6\x93\x8e\xe3\x80\x81\xe8\x87\xb4\xe5\x8a\x9b\xe4\xba\x8e\xe8\xae\xa9\xe7\xbd\x91\xe6\xb0\x91\xe6\x9b\xb4\xe4\xbe\xbf\xe6\x8d\xb7\xe5\x9c\xb0\xe8\x8e\xb7\xe5\x8f\x96\xe4\xbf\xa1\xe6\x81\xaf\xef\xbc\x8c\xe6\x89\xbe\xe5\x88\xb0\xe6\x89\x80\xe6\xb1\x82\xe3\x80\x82\xe7\x99\xbe\xe5\xba\xa6\xe8\xb6\x85\xe8\xbf\x87\xe5\x8d\x83\xe4\xba\xbf\xe7\x9a\x84\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91\xe9\xa1\xb5\xe6\x95\xb0\xe6\x8d\xae\xe5\xba\x93\xef\xbc\x8c\xe5\x8f\xaf\xe4\xbb\xa5\xe7\x9e\xac\xe9\x97\xb4\xe6\x89\xbe\xe5\x88\xb0\xe7\x9b\xb8\xe5\x85\xb3\xe7\x9a\x84\xe6\x90\x9c\xe7\xb4\xa2\xe7\xbb\x93\xe6\x9e\x9c\xe3\x80\x82"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="search" type="application/opensearchdescription+xml" ...
...
'''
# 返回当前环境的有关信息
print(response.info())
'''
Bdpagetype: 1
Bdqid: 0x0932eb0001c8f
Cache-Control: private
Content-Type: text/html;charset=utf-8
Date: Thu, 22 Apr 2021 02:28:48 GMT
Expires: Thu, 22 Apr 2021 02:27:56 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: BWS/1.1
Set-Cookie: BAIDUID=1153AD40DBAF90F5435353FC10B:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=214453447; path=/; domain=.baidu.com
Set-Cookie: BIDUPSID=1153AD40DBAF90F5432D31787A9FC10B; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: PSTM=163534548; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BAIDUID=1153AD35DBAF90F65468EA7EB4533595:FG=1; max-age=345435300; expires=Fri, 22-Apr-22 02:28:48 GMT; domain=.baidu.com; path=/; version=1; comment=bd
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33345_3345_315353_3364_3465_265740_28657; path=/; domain=.baidu.com
Traceid: 1745674674688087589780678584646519
Vary: Accept-Encoding
Vary: Accept-Encoding
X-Ua-Compatible: IE=Edge,chrome=1
Connection: close
Transfer-Encoding: chunked'''
# 返回状态码
print(response.getcode()) # 200
# if response.getcode() == 200 or response.getcode() == 304:
# 处理网页信息
# pass
# 返回当前只在爬取的URL地址
print(response.geturl()) # http://www.baidu.com
3.urllib.parse模块
常用方法
- urlencode(字典)
- quote(字符串) (这个里面的参数是个字符串)
示例1
import urllib.request
# 如何编码 3个%是一个汉字
url = 'https://tieba.baidu.com/f?fr=wwwt&ie=utf-8&kw=%E7%BE%BD%E5%93%A5'
url1 = 'https://tieba.baidu.com/f?fr=wwwt&ie=utf-8&kw=羽哥'
# res = urllib.request.urlopen(url1)
# 如果我通过urllib向一个携带中文字样的url发起请求,这个时候需要注意把中文转换为 % + 十六进制 的这种数据类型:%E7%BE%BD%E5%93%A5
import urllib.parse
wd = {'wd': '羽哥'}
result = urllib.parse.urlencode(wd)
print(result) # wd=%E7%BE%BD%E5%93%A5
new_url = 'https://tieba.baidu.com/f?fr=wwwt&ie=utf-8&' + result
示例2
# 示例2
import urllib.request
url2 = "https://tieba.baidu.com/f?kw=%E7%BE%BD%E5%93%A5"
# 解码
newUrl = urllib.request.unquote(url2)
print(newUrl)
'''
https://tieba.baidu.com/f?kw=羽哥'''
# 编码
newUrl2 = urllib.request.quote(newUrl)
print(newUrl2)
'''
https%3A//tieba.baidu.com/f%3Fkw%3D%E7%BE%BD%E5%93%A5'''
案例1:爬取王者荣耀高清壁纸
```python
# 爬取王者荣耀高清壁纸
# 网页分析:
# 主页: https://pvp.qq.com/web201605/wallpaper.shtml
# 第一页:https://pvp.qq.com/web201605/wallpaper.shtml
# 最后一页:https://pvp.qq.com/web201605/wallpaper.shtml 网址一样,说明下一页的图片是动态加载
# 每一页图片数量4*5=20张,共25页(第25页是6张图),一共20*24+6=486张高清图
# 第一张图地址:http://shp.qpic.cn/ishow/2735042018/1618915966_84828260_2160_sProdImgNo_7.jpg/0
# 第二张图地址:http://shp.qpic.cn/ishow/2735041519/1618485631_84828260_22420_sProdImgNo_7.jpg/0
# 第三张图地址:http://shp.qpic.cn/ishow/2735040920/1617970550_84828260_22886_sProdImgNo_7.jpg/0
# 第486张图地址:http://shp.qpic.cn/ishow/2735122518/1545733077_-888937974_7302_sProdImgNo_7.jpg/0
# No_2表示分辨率:1024x768,No_5表示分辨率:1440x900,No_7表示分辨率:1920x1200 图片地址结尾是.jpg/0
# 第1页js加载出来的数据:地址为https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=0&iOrder=0&iSortNumClose=1&jsoncallback=jQuery17103347171427601099_1619236609881&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1619236924589
# 第2页js加载出来的数据:地址为https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=1&iOrder=0&iSortNumClose=1&jsoncallback=jQuery17103347171427601099_1619236609882&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1619237018804
# 第25页js加载出来的数据:地址为https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=24&iOrder=0&iSortNumClose=1&jsoncallback=jQuery17103347171427601099_1619236609886&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1619237111998
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import re
import urllib.parse
class WangzheSpider:
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36'}
def get_url(self):
urls = []
for i in range(25):
url = 'https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page={}&iOrder=0&iSortNumClose=1&jsoncallback=jQuery17103347171427601099&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735'.format(
i)
urls.append(url)
return urls
def req_page(self, url, headers):
reponse = requests.get(url, verify=False, headers=self.headers).content
return reponse
def write_page(self, html, filename):
print('正在保存%s' % filename)
response = self.req_page(html,headers=self.headers)
with open(filename,'wb')as f:
f.write(response)
print('%s保存完毕' % filename)
def main(self):
urls = self.get_url()
hero_names = []
hero_images = []
for i in urls:
response = self.req_page(i, headers=self.headers).decode('utf-8')
pat1 = r'"sProdImgNo_7":"(.*?)",'
content1 = re.compile(pat1, re.S)
sProdImgNo_7_list = content1.findall(response)
image_address_list = []
for item in sProdImgNo_7_list:
i = urllib.parse.unquote(item)
image_address_list.append(i)
# print(image_address_lists, len(image_address_lists))
hero_images += image_address_list
pat2 = r'"sProdName":"(.*?)",'
content2 = re.compile(pat2, re.S)
sProdName_list = content2.findall(response)
hero_name_list = []
for item in sProdName_list:
i = urllib.parse.unquote(item)
hero_name_list.append(i)
# print(hero_name_list, len(hero_name_list))
hero_names += hero_name_list
# print(hero_names,hero_images)
finall_list = zip(hero_names, hero_images)
for i in finall_list:
html = i[1].replace('7.jpg/200', '5.jpg/0')
filename = './image/%s.jpg' % i[0]
self.write_page(html, filename)
if __name__ == '__main__':
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
spider = WangzheSpider()
spider.main()
发送 POST请求
示例:# 简单的翻译小软件
# 需求简单的翻译小软件
import urllib.request
import urllib.parse
import json
# 请输入您要翻译的内容
content = input("请输入您要翻译的内容:")
# 目标url 发请求
# url = 'https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' # 需要去掉其中的'_o',否则返回 {"errorCode":50}
url = 'https://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': '省略'}
# 携带数据
data = {
'i': content,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '16100656169337',
'sign': '94a4176fmdr3lc0rcb9e8r410ra3a158',
'lts': '1619064616935',
'bv': 'b77c859e9me719deegcc45c5s42bda',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME',
}
data = urllib.parse.urlencode(data)
data = bytes(data, 'utf-8')
req = urllib.request.Request(url, data=data, headers=headers)
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')
# print(html)
'''{"type":"ZH_CN2EN","errorCode":0,"elapsedTime":0,"translateResult":[[{"src":"你好","tgt":"hello"}]]}''' # 这是一个json类型的字符串。
# 解析数据
# json类型的str --> python类型的字典
r_dict = json.loads(html)
print(r_dict['translateResult'][0][0]['tgt'])
'''
请输入您要翻译的内容:你好
hello'''
5.练习1:输入指定内容在百度中搜索,并保存网页内容
import urllib.parse
import urllib.request
# url = "https://www.baidu.com/s?wd=%E7%BE%BD%E5%93%A5"
# 构造url
key = input("请输入要搜索的内容:")
wd = {'wd': key}
result = urllib.parse.urlencode(wd) # 编码
url = 'https://www.baidu.com/s?' + result
# 创建请求对象
headers = {
'User-Agent': '省略'}
req = urllib.request.Request(url, headers=headers)
# 获取响应对象
response = urllib.request.urlopen(req)
# 读取数据
html = response.read().decode('utf-8')
# 保存数据
with open('%s.html' % key, 'w', encoding='utf-8')as f:
f.write(html)
6.练习2:输入指定内容在百度贴吧中搜索,并保存多个网页内容
# 百度贴吧练习
# 输入要爬取的贴吧主题
# 进行翻页爬取 起始页和终止页
# 保存数据
import urllib.parse
import urllib.request
# 1.分析网页:
'''
第一页:https://tieba.baidu.com/f?kw=%E5%92%8C%E5%B9%B3%E7%B2%BE%E8%8B%B1&ie=utf-8&pn=0
第二页:https://tieba.baidu.com/f?kw=%E5%92%8C%E5%B9%B3%E7%B2%BE%E8%8B%B1&ie=utf-8&pn=50
最后一页:https://tieba.baidu.com/f?kw=%E5%92%8C%E5%B9%B3%E7%B2%BE%E8%8B%B1&ie=utf-8&pn=506500
共10131页'''
# url = "https://tieba.baidu.com/f?"
# 2.构造url
name = input("请输入要搜索的贴吧名称:")
begin = int(input("请输入起始页:"))
end = int(input("请输入结束页:"))
kw = {'kw': name}
result = urllib.parse.urlencode(kw)
for i in range(begin, end + 1):
pn = (i - 1) * 50
url = 'https://tieba.baidu.com/f?' + result + '&pn=' + str(pn) # 可省略&ie=utf-8
# 3.创建请求对象
headers = {
'User-Agent': '省略'}
req = urllib.request.Request(url, headers=headers,)
# 4.获取响应对象
res = urllib.request.urlopen(req, timeout=20)
# 读取数据
html = res.read().decode('utf-8')
# 保存数据
with open('第%d页.html' % i, 'w', encoding='utf-8')as f:
print('正在爬取第%d页.html' % i)
f.write(html)
'''
请输入要搜索的贴吧名称:和平精英
请输入起始页:1
请输入结束页:3
正在爬取第1页.html
正在爬取第2页.html
正在爬取第3页.html
'''
7.优化代码
# 练习:输入指定内容在百度贴吧中搜索,并保存多个网页内容
import urllib.parse
import urllib.request
class BaiduSpider:
def __init__(self):
self.headers = {
'User-Agent': '省略'}
self.base_url = 'https://tieba.baidu.com/f?'
def readPage(self, url, headers):
req = urllib.request.Request(url, headers=self.headers)
res = urllib.request.urlopen(req, timeout=20)
html = res.read().decode('utf-8')
return html
def writePage(self, filename, html):
with open(filename, 'w', encoding='utf-8')as f:
f.write(html)
print('写入成功')
def main(self):
name = input("请输入要搜索的贴吧名称:")
begin = int(input("请输入起始页:"))
end = int(input("请输入结束页:"))
kw = {'kw': name}
result = urllib.parse.urlencode(kw)
for i in range(begin, end + 1):
pn = (i - 1) * 50
url = self.base_url + result + '&pn=' + str(pn)
html = self.readPage(url, headers=self.headers)
filename = './file/第%d页.html' % i
self.writePage(filename, html)
if __name__ == '__main__':
spider = BaiduSpider()
spider.main()
'''
请输入要搜索的贴吧名称:法拉利
请输入起始页:5
请输入结束页:8
写入成功
写入成功
写入成功
写入成功'''
二、requests模块
1.安装
- pip install requests
- 在开发工具中安装
2.requests常用方法
- requests.get(网址)
示例1
import requests
r = requests.get('http://www.baidu.com/').text
print(r) # 返回网页数据
示例2
import requests
'''
response = requests.get(url, headers=headers)
1.url是最基本的url 不包含参数的
2.params中的键值对为参数
response = requests.get(url, params=params, headers=headers)
'''
# 示例1
# https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B
url = 'https://tieba.baidu.com/f?'
params = {'kw': '海贼王', 'pn': '250'}
headers = {
'User-Agent': '省略'}
response1 = requests.get(url, params=params, headers=headers, verify=False)
# print(response1.text) # 成功返回百度贴吧关于海贼王的第6页html数据
# 示例2
# https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B
url = 'https://tieba.baidu.com/f?kw=海贼王&pn=250'
headers = {
'User-Agent': '省略'}
response2 = requests.get(url, headers=headers, verify=False)
# print(response2.text) # 成功返回百度贴吧关于海贼王的第6页html数据
# 示例3
url = 'https://qq.yh31.com/zjbq/2920180.html'
headers = {
'User-Agent': '省略'}
response3 = requests.get(url, headers=headers, verify=False)
# print(response3.text) # 显示<title>喜羊羊QQ表æƒ
,å¯çˆ±çš„懒羊羊æžç¬‘图片_第1页_表æƒ
å
š</title>
# print(response3.content.decode('utf-8')) # 正常返回html数据
'''
response.content 它是直接从网站上抓取数据,没有做任何处理
response.text 它是requests模块将response.content编码之后所得到的数据
requests就会猜一个解码方式
如果出现乱码
第一种方式
response.content.decode('utf-8')
第二种方式
response3.encoding='utf-8'
print(response3.text)
'''
3.响应对象response的方法
- response.text 返回unicode格式的数据(str)
- response.content 返回字节流数据(二进制)
- response.content.decode(‘utf-8’) 手动进行解码
- response.url 返回url
- response.encoding=‘utf-8’
print(response.text)
示例
import requests
r = requests.get('http://www.baidu.com')
print(r.text)
'''
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta
...
...
href=http://jianyi.baidu.com/ class=cp-feedback>æ„è§å馈</a> 京ICPè¯030173å· <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
'''
print(r.content)
'''
b'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min
...
...
src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>\r\n'
'''
print(r.content.decode('utf-8'))
'''
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta
...
...
Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
'''
print(r.url) # http://www.baidu.com/
r.encoding = 'utf-8'
print(r.text)
'''
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta
...
...
Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
'''
4.requests模块发送 POST请求
示例1
import requests
r = requests.post('http://httpbin.org/post', data={'key': 'value'}).text
print(r) # 正常返回网页数据
'''
{
"args": {},
"data": "",
"files": {},
"form": {
"key": "value"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "9",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.25.1",
"X-Amzn-Trace-Id": "Root=1-6083f17f-02c7589e52e792b40c5960af"
},
"json": null,
"origin": "省略",
"url": "http://httpbin.org/post"
}'''
示例2:简单的翻译小软件
# 简单的翻译小软件
import requests
import json
# 请输入您要翻译的内容
content = input("请输入您要翻译的内容:")
# 目标url 发请求
# url = 'https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' # 需要去掉其中的'_o',否则返回 {"errorCode":50}
url = 'https://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0'}
# 携带数据
data = {
'i': content,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '16190646169357',
'sign': '94a417e26fdc3c0cb59e843108a3a158',
'lts': '1619064616935',
'bv': 'b77c8593ce9e7129dee4cc45ac542b2a',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME',
}
response = requests.post(url, data=data, headers=headers, verify=False)
html = response.text
# print(html)
'''{"type":"ZH_CN2EN","errorCode":0,"elapsedTime":0,"translateResult":[[{"src":"你好","tgt":"hello"}]]}''' # 这是一个json类型的字符串。
# 解析数据
# json类型的str --> python类型的字典
r_dict = json.loads(html)
print(r_dict['translateResult'][0][0]['tgt'])
'''
请输入您要翻译的内容:猫
The cat'''
示例3:简单的翻译小软件,通过js逆向
第一步:确定url:https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
第二步:查看请求里携带的参数,分析
i: 中国
from: AUTO
to: AUTO
smartresult: dict
client: fanyideskweb
salt: 16195811191097
sign: ffc58c4904e3b84538f1a324b00a141d
lts: 1619581119109
bv: b77c8593ce9e7129dee4cc45ac542b2a
doctype: json
version: 2.1
keyfrom: fanyi.web
action: FY_BY_REALTlME
重点解决
salt: 16195811191097
sign: ffc58c4904e3b84538f1a324b00a141d
lts: 1619581119109
这三个参数的问题
双击Initiator里面的 fanyi.min.js:1文件,点击{},查看json文件。
Ctrl+F 查找‘salt’,
首先:r = “” + (new Date).getTime()
复制(new Date).getTime()到Console里查看它,发现它是一个13位数字的时间戳
写入模仿时间戳的程序:
import time
r = str(int(time.time()*1000))
其次:i = r + parseInt(10 * Math.random(), 10),parseInt(10 * Math.random(), 10)为0到9的随机值。
模拟生成i:
import random
i = random.randint(0, 9)
i = r + str(i)
最后:sign: n.md5(“fanyideskweb” + e + i + “Tbh5E8=q6U3EXe+&L[4c@”),它是md5加密,先找到e,设置断点查看e是啥?原来就是输入的内容
模拟生成sign
import hashlib
def data_new(e):
str_sign = “fanyideskweb” + e + i + “Tbh5E8=q6U3EXe+&L[4c@”
md5 = hashlib.md5()
md5.update(str_sign.encode())
sign = md5.hexdigest()
# print(sign) # e8b710fe24c560f01dbb1f724899bdfd
data = {
‘i’: e,
‘from’: ‘AUTO’,
‘to’: ‘AUTO’,
‘smartresult’: ‘dict’,
‘client’: ‘fanyideskweb’,
‘salt’: i,
‘sign’: sign,
‘lts’: r,
‘bv’: ‘b77c8593ce9e7129dee4cc45ac542b2a’,
‘doctype’: ‘json’,
‘version’: ‘2.1’,
‘keyfrom’: ‘fanyi.web’,
‘action’: ‘FY_BY_REALTlME’,
}
return data
data = data_new(e)
# 简单的翻译小软件 不去掉'_o',进行js逆向
# 分析:
# 'salt': '16190646169357',
# 'sign': '94a417e26fdc3c0cb59e843108a3a158',
# 'lts': '1619064616935',
import random
import time
import requests
import json
import hashlib
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
e = input("请输入您要翻译的内容:")
r = str(int(time.time()*1000))
i = random.randint(0, 9)
i = r + str(i)
# print(r,i)
# 目标url
url = 'https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36',
'Referer': 'https://fanyi.youdao.com/',
'Cookie': '你的cookie'
}
# 携带数据
def data_new(e):
str_sign = "fanyideskweb" + e + i + "Tbh5E8=q6U3EXe+&L[4c@"
md5 = hashlib.md5()
md5.update(str_sign.encode())
sign = md5.hexdigest()
# print(sign) # e8b710fe24c560f01dbb1f724899bdfd
data = {
'i': e,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': i,
'sign': sign,
'lts': r,
'bv': 'b77c8593ce9e7129dee4cc45ac542b2a',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME',
}
return data
data = data_new(e)
response = requests.post(url, data=data, headers=headers, verify=False)
html = response.text
print(html)
'''{"translateResult":[[{"tgt":"The fox","src":"狐狸"}]],"errorCode":0,"type":"zh-CHS2en","smartResult":{"entries":["","[脊椎] fox\r\n"],"type":1}}{"type":"ZH_CN2EN","errorCode":0,"elapsedTime":0,"translateResult":[[{"src":"你好","tgt":"hello"}]]}''' # 这是一个json类型的字符串。
# 解析数据
# json类型的str --> python类型的字典
r_dict = json.loads(html)
print(r_dict['translateResult'][0][0]['tgt'])
'''
请输入您要翻译的内容:狐狸
The fox'''
5.requests设置代理
# 代理ip
# 爬虫去爬取别的网站数据的时候,如果短时间内爬取的频次过高或者一些其他的原因,被对方识别出是爬虫后
# 需要换个ip 就需要通过代理ip来解决 应对反爬策略
# 作用 1.隐藏真实的ip 2.应对反爬的策略
# 代理ip的匿名度 1.透明:服务器知道你使用了代理ip,也知道你的真实ip 2.匿名:知道你使用了代理ip,不知道你的真实ip
# 3.高匿 不知道你使用了代理ip,也不知道你的真实ip
# 使用豌豆ip代理:1.注册 2.设置白名单(加入自己外网的ip) 3.点击工具--提取api
import requests
url = 'http://httpbin.org/ip'
# 设置代理
ips = [
'223.240.245.57:23564',
'223.241.51.205:3617',
'114.232.64.153:36410',
'183.141.100.99:3617',
'61.191.85.17:36410',
'114.98.148.7:36410',
'60.174.189.138:766',
'117.57.21.134:3617',
'117.70.39.253:5412',
'114.227.163.5:766',
'125.123.120.238:36410',
'114.100.1.181:3617',
'42.59.102.21:23564',
'183.92.238.218:36410',
'121.233.207.1:5412',
'223.240.247.104:3617',
'60.174.188.26:36410',
'182.87.241.109:766',
'114.227.11.169:766',
'218.91.0.33:894',
]
available_list = []
for i in range(20):
ip = ips[i]
print(ip)
try:
response = requests.get(url, proxies={'http': ip}, timeout=0.5)
print(response.text)
available_list.append(ip)
except Exception as e:
print("出现异常")
print(available_list)
'''
['114.232.64.153:36410']'''
6.处理不信任的SSL证书
什么是SSL证书?
- SSL证书是数字证书的一种,类似于驾驶证,护照和营业执照的电子副本因为配置在服务器上,也称为SSL服务器证书.SSL证书就是遵守SSL协议,由受信任的数字证书颁发机构CA,在验证服务器身份后提交,具有服务器身份验证和数据传输加密功能
测试网站https://inv-veri.chinatax.gov.cn/
示例
import requests
# response = requests.get('https://inv-veri.chinatax.gov.cn/').text
# print(response)
'''
requests.exceptions.SSLError: HTTPSConnectionPool(host='inv-veri.chinatax.gov.cn', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)')))'''
response = requests.get('https://inv-veri.chinatax.gov.cn/', verify=False).text
print(response) # 正常返回网页数据
7.cookie
cookie:通过在客户端记录的信息确定用户身份HTTP是一种无连接协议,客户端和服务器交互仅连接请求/响应过程,结束后重新连接,下一次请求时,服务器会认为是一个新的客户端,为了维护他们之间的连接,让服务器知道这是前一个用户发起的请求,必须在一个地方保存客户端信息。
作用:
1.模拟登录
模拟登录知乎
目标url: ‘https://www.zhihu.com/hot’
发起请求,获取响应
示例1
# 模拟登录知乎
# 目标 url=https://www.zhihu.com/hot
# 发起请求,获取响应
import requests
url = 'https://www.zhihu.com/hot'
headers = {
'Cookie': '省略',
'User-Agent': '省略'
}
response = requests.get(url, headers=headers).text
print(response) # 因为没有登录,所有无法显示登录之后的页面,添加'Cookie',可以返回正常数据
2.反反爬机制
12306官网
查票 杭州-上海 5号 -->查询
第一个问题:为什么页面中有数据而在网页的源码中没有呢?
总结:在网页中有数据,而在源代码中没有数据,是不是服务器传输了多次数据,导致我们在网页源代码中没有找到
第二个问题:G9314关键字如何找出来呢?
网页整体没有发生变化,但是局部发生了变化,ajax
解决方法:
1.分析它真正的数据接口query
2.通过selenium
示例2
import re
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
class Ticket12306:
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 '
}
def requests_url(self, cookie, url):
cookie.update(self.headers)
response = requests.get(url, headers=cookie, verify=False)
response.encoding = 'utf-8'
return response
def get_station(self, cookie, url):
response = self.requests_url(cookie, url)
station = re.findall(r'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text) # \u4e00-\u9fa5代表所有的中文字符,也就是找到一个中文和与之对应的英文字符
# 将列表转成字典
station_data = dict(station)
# 将键和对应的值互换
station_names = {} # 空字典,用于将key和value进行交换
for item in station_data:
station_names[station_data[item]] = item
return station_names
def main(self, cookie_1, url_1, cookie_2, url_2):
response = self.requests_url(cookie_1,url_1,)
json_tickets = response.json()
data_list = json_tickets['data']['result']
station_names = self.get_station(url=url_2, cookie=cookie_2)
for item in data_list:
data = item.split('|')
l = list(data[13])
l.insert(4, "-")
l.insert(7, "-")
data[13] = ''.join(l)
print("车次:" + data[3],
"出发站:" + station_names[data[6]],
"到达站:" + station_names[data[7]],
"出发时间:" + data[8],
"到达时间:" + data[9],
"历时:" + data[10],
"是否可预订:" + data[11],
"始发站:" + station_names[data[4]],
"终点站:" + station_names[data[5]],
"出行时间:" + data[13],
"商务特等座:" + data[32],
"一等座:" + data[31],
"二等座/二等包座:" + data[30],
"高级软卧" + data[21],
"软卧/一等卧:" + data[23],
"动卧:" + data[33],
"硬卧/二等卧:" + data[28],
"软座" + data[24],
"硬座:" + data[29])
if __name__ == '__main__':
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
get_ticket_12306 = Ticket12306()
cookie_1 = {
'Cookie': '省略', }
url_1 = 'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2021-05-05&leftTicketDTO.from_station=HZH&leftTicketDTO.to_station=SHH&purpose_codes=ADULT'
cookie_2 = {
'Cookie': '省略'}
url_2 = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9188'
get_ticket_12306.main(cookie_1, url_1, cookie_2, url_2)
总结:
发现每个数据以‘|’分隔的这个时候,我们需要知道个别数据的位置
以‘|’进行分隔,通过列表的下标索引值就可以知道个别数据的位置,就可以做后期的逻辑编写
8.会话
session:通过在服务端记录的信息确定用户身份,此处这个session指的是会话
案例:突破12306图片验证
网址:https://kyfw.12306.cn/otn/resources/login.html
1.账号正确,密码错误,验证码错误
2.账号正确,密码错误,验证码正确
3.账号正确,密码正确,验证码正确 ok
-
第1种情况:
查看验证码错误下加载的js文件
返回的结果为:/**/jQuery191018415675635795536_1619398855906({result_message: “验证码校验失败”, result_code: “5”}); -
第2种情况:
Request URL: https://kyfw.12306.cn/passport/captcha/captcha-check?callback=jQuery19109716061695448353_1619405746616&answer=197%2C45&rand=sjrand&login_site=E&_=1619405746618
携带的参数:
callback: jQuery19109716061695448353_1619405746616
answer: 197,45
rand: sjrand
login_site: E
_: 1619405746618
返回的结果为:/**/jQuery19109716061695448353_1619405746616({“result_message”:“验证码校验成功”,“result_code”:“4”}); -
同时加载了XHR的login文件:
Request URL: https://kyfw.12306.cn/passport/web/login
携带参数:
sessionId: 01d2TIqaddEzxCU28_GKB5Vcx6pP744fcOUyRfChk3c8ipKNCQPUrw6EEG98nN5ql6XKac_gGEGflLST6xpxnGguWMsIsoEuz0kKp9vrymPCFPwwIWh5-mCKTHbuJ6JjJm9GOGs3FoKnRG4ekQumkiHipl-wh1fnhhp61Bca3DA7Eovt_bdEryA7r-P1XrPVhVRegW3nON-AG5VHfGAR7ESg
sig: 05XqrtZ0EaFgmmqIQes-s-CJXzPZeUryxboUG9ElN6m-Gluzj13p46YPFqGVUE13mwXLW9LePExNtTkfJbYwQx-SiDQkK0HgJuFMYzM4p78PFxKeRNvi0NcYUY_IvyYkChfVWcqh3BWyF92Tiszkl7vqhX7-KltDfOK_bDcSEC2-Bm7srz5Pm38t5tc6pY-tmg-CO_6Z8xNxewxRapD0iP30diKryST_sDaSZDYJNFYHFaUJU2g-Dpi_XenL-nsYWqCD7RBriG6_I3-IMPUHLq6d5yFpBFfH7act7AMeQErOAkktFlZ9147ZpgWCtCYmyosyaBjFn8j4_HQW9ZQlh_Agxq8w7fEASqbOQNfLm2HUM1Z6zD-wn314_uKIkFv2QiTQSNCXnM8LKGpZ9NRO_5J3FdUaNyYgPBu0uZ1chQAtaDXVkPG-z0HdogKCoeBSAyBEdv5Sx7EdbjOaTUSbuyiuhheYynx6CpZ6ZE0aItv3A
if_check_slide_passcode_token: FFFF0N000000000085DE:1619405993688:0.096504509317295041
scene: nc_login
tk:
username: 18582868483
password: @grRrViQiBQgpTr59DNzcVw==
appid: otn
逻辑:首先要验证码正确,才能向网页提交用户、密码请求。
1.明确目标url:https://kyfw.12306.cn/passport/captcha/captcha-check
2.发送post请求,并携带数据:
callback: jQuery19109716061695448353_1619405746616
answer: 197,45
rand: sjrand
login_site: E
_: 1619405746618
3.获取12306图片验证码
方法一:
在网页中点击鼠标右键,复制图片地址为:
img_url=‘data:image/jpg;base64,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’
# base64伪加密:根本不算是一种加密算法,只不过它的数据看上去更像密文而已
# 64个字符来表示任意的二进制数据的方法
# 使用A-Z a-z 0-9 + / 这64个字符进行加密
import base64
img = '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'
img_data = base64.b64decode(img) # 返回的是二进制数据
print(type(img_data)) # <class 'bytes'>
fn = open('code.png', 'wb')
fn.write(img_data)
fn.close()
'''
我们打开了一个有base64加密的图片数据
binascii.Error: Incorrect padding填充不正确
去掉头部的data:image/jpg;base64,
'''
方法二:
第一步:获取验证码图片的请求地址Request URL: https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&1619414089185&callback=jQuery19109716061695448353_1619405746616&_=1619405746621
第二步:浏览器打开查看数据: https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand
第三步:去掉浏览器地址里的64
总结:https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand 请求图片不使用64伪加密
4.点击正确的图片
# 突破12306图片验证码
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
req = requests.session() # 保持会话
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36'}
def get_img():
# 获取验证码图片
pic_response = req.get(
'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand', headers=headers,verify=False).content
with open('code.png', 'wb')as f:
f.write(pic_response)
def login():
# 从验证码图片的左上角开始截屏获取位置坐标
codeStr = input('请输入验证码坐标:')
data = {
'answer': codeStr,
'rand': 'sjrand',
'login_site': 'E'
}
response = req.post('https://kyfw.12306.cn/passport/captcha/captcha-check', data=data, headers=headers,verify=False)
print(response.text) # {"result_message":"验证码校验失败,信息为空","result_code":"8"}
get_img()
login()
'''
请输入验证码坐标:50,40,185,114
{"result_message":"验证码校验成功","result_code":"4"}'''