先用之前学到过的方法解决
先创建一个爬取图片.py 在新标签页中打开图片
这就是该图片的url
import requests
#图片的url
url='https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1596188551&di=3c06d3cd21c706c6c9c562f2bf76f56e&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg'
req=requests.get(url)
fn=open('code.png','wb')
fn.write(req.content)
fn.close()
import requests
url='https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1596188551&di=3c06d3cd21c706c6c9c562f2bf76f56e&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg'
req=requests.get(url)
#
# fn=open('code.png','wb')
# fn.write(req.content)
#
# fn.close()
with open('code2.png','wb') as f:
f.write(req.content)
import requests
from urllib import request
url='https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1596188551&di=3c06d3cd21c706c6c9c562f2bf76f56e&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg'
request.urlretrieve(url,'code3.png')
# req=requests.get(url)
#
# fn=open('code.png','wb')
# fn.write(req.content) #content只是二进制数据
#
# fn.close()
#
# with open('code2.png','wb') as f:
# f.write(req.content)
python2 :urllib2、urllib
python3 :把urllib和urllib2合并,urllib.request
• urllib.request.urlopen(“网址”) 作用 :向网站发起一个请求并获取响应 (或者是直接获取响应)
• 字节流 = response.read()
• 字符串 = response.read().decode(“utf-8”)
• urllib.request.Request"网址",headers=“字典”) urlopen()不支持重构User-Agent
新建一个python文件
import urllib.request
# 向百度发起一个请求 得到一个响应结果 用一个变量接收
response=urllib.request.urlopen('https://www.baidu.com/')
print(response)
<http.client.HTTPResponse object at 0x0000000002504E20>
是一个对象
import urllib.request
# 向百度发起一个请求 得到一个响应结果 用一个变量接收
response=urllib.request.urlopen('https://www.baidu.com/')
#从响应对象中获取数据 read()函数来读取数据
print(response.read())
b'\r\n\r\n\t\r\n\r\n\r\n\t\r\n\r\n'
咱们拿到的这个response数据应该是网页源码 但是这些太少了
咱们拿到的网页源码应该是这些
上面操作拿到的显然太少了 原因是百度在这里做了反爬了
咱们换个网站 一会再解决这个问题
但是没有文字
因为
这个b bit数据类型 字节
可以查看它的类型
import urllib.request
# 向百度发起一个请求 得到一个响应结果 用一个变量接收
response=urllib.request.urlopen('https://qq.yh31.com/')
#从响应对象中获取数据 read()函数来读取数据
# print(response.read())
html=response.read()
print(type(html))
<class 'bytes'> 类型是字节
但是现在我想看到的是字符串类型
字节转换成字符串 用解码 decode
import urllib.request
# 向百度发起一个请求 得到一个响应结果 用一个变量接收
response=urllib.request.urlopen('https://qq.yh31.com/')
#从响应对象中获取数据 read()函数来读取数据
# print(response.read())
html=response.read().decode('utf-8')
print(html)
这会就正常了 因为源码实在太多了
咱们再来搞一搞刚才百度的反爬 可能是我们没有添加headers 请求头
import urllib.request
# 向百度发起一个请求 得到一个响应结果 用一个变量接收
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
response=urllib.request.urlopen('https://www.baidu.com/',headers=headers)
#从响应对象中获取数据 read()函数来读取数据
# print(response.read())
html=response.read().decode('utf-8')
print(html)
TypeError: urlopen() got an unexpected keyword argument 'headers'
类型错误:urlopen()获得意外的关键字参数“headers”
• urllib.request.Request"网址",headers=“字典”)
import urllib.request
# 请求百度的数据(网页源码)
url='https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
#1.创建请求对象(构建User-Agent)
response=urllib.request.Request(url,headers=headers)
#2.获取响应对象(urlopen())
res=urllib.request.urlopen(response)
#3.读取响应对象的内容(read().decode('utf-8'))
html=res.read().decode('utf-8')
print(html)
• read() 读取服务器响应的内容 (读取到的是一个字节流数据 所以后面要加上.decode())
• getcode() 返回HTTP的响应码
• geturl() 返回实际数据的URL(防止重定向问题)
import urllib.request
# 请求百度的数据(网页源码)
url='https://www.baidu.com/'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
#1.创建请求对象(构建User-Agent)
response=urllib.request.Request(url,headers=headers)
#2.获取响应对象(urlopen())
res=urllib.request.urlopen(response)
#3.读取响应对象的内容(read().decode('utf-8'))
html=res.read().decode('utf-8')
# print(html)
print(res.getcode())#返回状态码
print(res.geturl())# 返回实际的请求网站
200
https://www.baidu.com/
urllib 是python自带的请求模块 request是第三方的请求模块
• urlencode(字典) 参数就是字典
• quote(字符串) (这个里面的参数是个字符串)
我们先用百度搜素海贼王
因为是get请求 请求参数会显示在url上
后面的参数我们先不看 我们先拿关键的部分
url='https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B'
我们发现海贼王没了 %E6%B5%B7%E8%B4%BC%E7%8E%8B
原因就是 我们在向一个网页发起请求的时候 比如在百度的搜素框里搜索一个中文 海贼王
也就是它要把中文向服务器提交 但是网站只能识别 ascii 码 也就是英文 它真正提交传输内容的时候是ascii码 是网站给你做了这么一个编码 网页是不识别中文的
所以海贼王变成了十六进制的这么个东西%E6%B5%B7%E8%B4%BC%E7%8E%8B
比如你搜索关键字 比如是用拼串 如果直接加上你要搜索的关键字 (比如美女) 那么你的程序就有可能会出现问题 所以我们要将汉字进行手动的编码
如何进行手动编码呢 就要用到urllib.parse模块的 urlencode( ) 的这个方法
我们先可以试试这个%E6%B5%B7%E8%B4%BC%E7%8E%8B 是不是就是海贼王
三个百分号为一个汉字
那么%E6%B5%B7 就是海 %E8%B4%BC就是贼 %E7%8E%8B就是王
可以使用工具urldecode解码
https://tool.chinaz.com/tools/urlencode.aspx
import urllib.parse
# url='https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B'
r={'wd':'海贼王'} #这个是字典 传集合 也就是没有键 是会报错的
result=urllib.parse.urlencode(r)
print(result)
wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
# 导入模块
import urllib.parse
import urllib.request
#在百度上输入一个内容 例如:美女 数据保存到本地文件 美女.html
#baseurl 初始url
baseurl='https://www.baidu.com/s?'#此处的s?比较重要 不能丢
content=input('你要搜索的内容:')
wd={'wd':content} #当然也可以是d={'wd':content} 前面的那个变量可以随便编 但是key值就是wb 这个不能错
content=urllib.parse.urlencode(wd)
#拼接url
url=baseurl+content
print(url)
你要搜索的内容:美女 #回车 此处可以自行输入内容
https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3
# 导入模块
import urllib.parse
import urllib.request
#在百度上输入一个内容 例如:美女 数据保存到本地文件 美女.html
#baseurl 初始url
baseurl='https://www.baidu.com/s?'#此处的s?比较重要 不能丢
content=input('你要搜索的内容:')
wd={'wd':content} #当然也可以是d={'wd':content} 前面的那个变量可以随便编 但是key值就是wb 这个不能错
content=urllib.parse.urlencode(wd)
#拼接url
url=baseurl+content
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
#创建请求对象
req=urllib.request.Request(url,headers=headers)
#获取响应对象
res=urllib.request.urlopen(req)
#读取
html=res.read().decode('utf-8')
#保存文件
with open('美女.html','w',encoding='utf-8')as f:
f.write(html)
反爬 ua refer cookie 可以把这些添加进去来反制一些反爬
• urlencode(字典) 参数就是字典
• quote(字符串) 这个里面的参数是个字符串
import urllib.parse
baseurl='https://www.baidu.com/s?'
r={'wd':'海贼王'}
result=urllib.parse.urlencode(r)
url=baseurl+result
print(url)
https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
quote(引用)
import urllib.parse
key=input('输入内容:')
baseurl='https://www.baidu.com/s?wd='
r=urllib.parse.quote(key)
url=baseurl+r
print(url)
输入内容:姑娘
https://www.baidu.com/s?wd=%E5%A7%91%E5%A8%98
二者区别应该也就是baseurl中的wd=
需求:
1输入要爬取贴吧的主题
2输入爬取的起始页和终止页
3把每一页的内容保存到本地
我们可以去网上搜索一些请求头
需求: 1输入要爬取贴吧的主题 2输入爬取的起始页和终止页 3把每一页的内容保存到本地
分析
https://tieba.baidu.com/f?kw=%E4%B8%AD%E5%9B%BD&ie=utf-8&pn=0 第一页
https://tieba.baidu.com/f?kw=%E4%B8%AD%E5%9B%BD&ie=utf-8&pn=50 第二页https://tieba.baidu.com/f?kw=%E4%B8%AD%E5%9B%BD&ie=utf-8&pn=100 第三页
pn=(当前页数-1)*50kw 贴吧的主题
import random
import urllib.request
import urllib.parse
#随机获取一个user-agent
headers_list = [{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'}]
headers=random.choice(headers_list)
name=input('请输入贴吧名:')
start=int(input('请输入起始页:'))
end=int(input('请输入结束页:'))
#对贴吧名name做个编码
kw={'kw':'%s'%name}
kw=urllib.parse.urlencode(kw)
#开始拼接url 发起请求 获取响应
for i in range(start,end+1):
#开始拼接url
pn=(i-1)*50
baseurl='https://tieba.baidu.com/f?'
url=baseurl+kw+'&pn='+str(pn)# 因为这是一个字符串的拼串
#创建请求对象
req=urllib.request.Request(url,headers=headers)
#获取响应对象
res=urllib.request.urlopen(req)
#读取
html=res.read().decode('utf-8')
#写入文件
filename='第'+str(i)+'页%s贴吧.html'%name
with open(filename,'w',encoding='utf-8') as f:
print('正在爬取%d页'%i)
f.write(html)
import urllib.request
import urllib.parse
#读取页面
def readPage(url):
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'}
req = urllib.request.Request(url, headers=headers)
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')
return html
#写入文件
def writePage(filename,html):
with open(filename, 'w', encoding='utf-8') as f:
f.write(html)
print('写入成功')
#主函数
def main():
name = input('请输入贴吧名:')
start = int(input('请输入起始页:'))
end = int(input('请输入结束页:'))
# 对贴吧名name做个编码
kw = {'kw': '%s' % name}
#kw = {'kw':name} 这样更简单
kw = urllib.parse.urlencode(kw)
# 开始拼接url 发起请求 获取响应
for i in range(start, end + 1):
# 开始拼接url
pn = (i - 1) * 50
baseurl = 'https://tieba.baidu.com/f?'
url = baseurl + kw + '&pn=' + str(pn) # 因为这是一个字符串的拼串
filename = '第' + str(i) + '页%s贴吧.html' % name
html=readPage(url)
writePage(filename,html)
if __name__ == '__main__':
main()
import urllib.request
import urllib.parse
class BaiduSpider:
def __init__(self):
#把常用的不变 的放到这里
self.headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'}
self.baseurl = 'https://tieba.baidu.com/f?'
def readPage(self,url):
req = urllib.request.Request(url, headers=headers)
res = urllib.request.urlopen(req)
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('请输入贴吧名:')
start = int(input('请输入起始页:'))
end = int(input('请输入结束页:'))
# 对贴吧名name做个编码
kw = {'kw':name}
kw = urllib.parse.urlencode(kw)
# 开始拼接url 发起请求 获取响应
for i in range(start, end + 1):
# 开始拼接url
pn = (i - 1) * 50
# baseurl = 'https://tieba.baidu.com/f?'这个就不用了
url = self.baseurl + kw + '&pn=' + str(pn) # 因为这是一个字符串的拼串
filename = '第' + str(i) + '页%s贴吧.html' % name
html = self.readPage(url)
self.writePage(filename, html)
if __name__ == '__main__':
#创建类的实例
spider=BaiduSpider()
spider.main()
请输入贴吧名:土狗
请输入起始页:1
请输入结束页:3
写入成功
写入成功
写入成功
• GET 特点 :查询参数在URL地址中显示
• POST
• 在Request方法中添加data参数 urllib.request.Request(url,data=data,headers=headers)
• data :表单数据以bytes类型提交,不能是str
就是比如图中的你好 这些数据 以post请求提交给服务器 提交到了form表单.
提交是手动提交的 我们可以做一个有道翻译小软件.
首先这个请求的url地址是可以帮我们做这个翻译的
就是
中的
http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
然后我们的输入内容会在form表单里面 这个表单里有些数据是变的 有些数据是不变的
你会发现这里面特别像字典 key-value
我们先把他们全部拿下来 复制 那么我们就可以把form表单里 的数据变成一个字典
然后再把这个字典类的数据以post的方式提交到上面说的url地址上
但是提交的时候我们用的是urllib 用其中的方法request.Request( ) 但是用它的额话 提交的数据得是一个字节 那么我们就得把字典数据类型转化成字节流
import urllib.parse
import urllib.request
#请输入要翻译的内容
key=input('请输入要翻译的内容:')
#把提交的form表单数据转换为byte类型数据
data={
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15880623642174',
'sign': 'c6c2e897040e6cbde00cd04589e71d4e',
'ts': '1588062364217',
'bv': '42160534cfa82a6884077598362bbc9d',
'doctype': 'json',
'version': '2.1',
'keyfrom':'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
data=urllib.parse.urlencode(data) #就是把字典这个数据做一个编码
#把date数据转换成字节流数据
data=bytes(data,'utf-8')
#发起请求 获取响应
url='http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
req=urllib.request.Request(url,data=data,headers=headers)
res=urllib.request.urlopen(req)
html=res.read().decode('utf-8')
print(html)
请输入要翻译的内容:好你妹
{"errorCode":50}
错误码 50 我们看看哪里错了
可能是他们的前端比较强 做过了处理
url=‘http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule’
我们把_o去掉
url中去掉 _o
import urllib.parse
import urllib.request
#请输入要翻译的内容
key=input('请输入要翻译的内容:')
#把提交的form表单数据转换为byte类型数据
data={
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15880623642174',
'sign': 'c6c2e897040e6cbde00cd04589e71d4e',
'ts': '1588062364217',
'bv': '42160534cfa82a6884077598362bbc9d',
'doctype': 'json',
'version': '2.1',
'keyfrom':'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
data=urllib.parse.urlencode(data) #就是把字典这个数据做一个编码
#把date数据转换成字节流数据
data=bytes(data,'utf-8')
#发起请求 获取响应
url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
req=urllib.request.Request(url,data=data,headers=headers)
res=urllib.request.urlopen(req)
html=res.read().decode('utf-8')
print(html,type(html))
请输入要翻译的内容:咦嘿嘿
{"type":"ZH_CN2EN","errorCode":0,"elapsedTime":5,"translateResult":[[{"src":"咦嘿嘿","tgt":"Hey hey hey"}]]}
<class 'str'>
翻译成了Hey hey hey …
而且看出了这个html类型是个str
原因就是
而控制台打印的结果 它会把引号省去
所以这个html 数据 是个字符串 json类型的字符串 它很像一个字典
我们需要导入一个json
import urllib.parse
import urllib.request
import json
#请输入要翻译的内容
key=input('请输入要翻译的内容:')
#把提交的form表单数据转换为byte类型数据
data={
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15880623642174',
'sign': 'c6c2e897040e6cbde00cd04589e71d4e',
'ts': '1588062364217',
'bv': '42160534cfa82a6884077598362bbc9d',
'doctype': 'json',
'version': '2.1',
'keyfrom':'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
data=urllib.parse.urlencode(data) #就是把字典这个数据做一个编码
#把date数据转换成字节流数据
data=bytes(data,'utf-8')
#发起请求 获取响应
url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
req=urllib.request.Request(url,data=data,headers=headers)
res=urllib.request.urlopen(req)
html=res.read().decode('utf-8')
#把json类型的字符串转换成字典
r_dict=json.loads(html) #这个操作后 这个jason类型的字符串就变成了了字典
print(r_dict,type(r_dict))
请输入要翻译的内容:f
{'type': 'EN2ZH_CN', 'errorCode': 0, 'elapsedTime': 0, 'translateResult': [[{'src': 'f', 'tgt': 'f'}]]} <class 'dict'>
而我们想要的是字典中键(key)tgt对应的值(value)
且从中我们可以看出 ‘translateResult’: [[{‘src’: ‘f’, ‘tgt’: ‘f’}]]
但是呢r是一个列表 我们的目标是取到此列表中的列表中的字典的值
所以
于是乎 可以有了更简单直接的方法
import urllib.parse
import urllib.request
import json
#请输入要翻译的内容
key=input('请输入要翻译的内容:')
#把提交的form表单数据转换为byte类型数据
data={
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15880623642174',
'sign': 'c6c2e897040e6cbde00cd04589e71d4e',
'ts': '1588062364217',
'bv': '42160534cfa82a6884077598362bbc9d',
'doctype': 'json',
'version': '2.1',
'keyfrom':'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
data=urllib.parse.urlencode(data) #就是把字典这个数据做一个编码
#把date数据转换成字节流数据
data=bytes(data,'utf-8')
#发起请求 获取响应
url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
req=urllib.request.Request(url,data=data,headers=headers)
res=urllib.request.urlopen(req)
html=res.read().decode('utf-8')
#把json类型的字符串转换成字典
r_dict=json.loads(html)
r=r_dict['translateResult']
content=r[0][0]['tgt']
print(content)
• pip install requests
• 在开发工具中安装
安装可以直接到我们的设置里面
这这里点右上角的加号
左下角的intsall package 安装
如果还是不行的话 我们可以换源安装
• requests.get(网址)
• response.text 返回unicode格式的数据(str)
• response.content 返回字节流数据(二进制)
• response.content.decode(‘utf-8’) 手动进行解码
• response.url 返回url
• response.encode() = ‘编码’
response.encode(‘utf-8’)
response.encoding=‘utf-8’
Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据。
后面的操作会用到后面用到时传入的data是一个字典
• 使用requests添加代理只需要在请求方法中(get/post)传递proxies参数就可以了
• 代理网站
快代理:http://www.kuaidaili.com/
代理云:http://www.dailiyun.com/
测试请求头网址: http://httpbin.org/user-agent
import requests
#IP #PORT(端口)
proxy={'http':'182.87.38.117:9000'}
url='http://httpbin.org/ip'
res=requests.get(url,proxies=proxy)
print(res.text)
run后结果是
又试了 好几个还是不行 果然免费的还是不靠谱
cookie :通过在客户端记录的信息确定用户身份
HTTP是一种无连接协议,客户端和服务器交互仅仅限于 请求/响应过程,结束后断开,下一次请求时,服务器会认为是一个新的客户端,为了维护他们之间的连接,让服务器知道这是前一个用户发起的请求,必须在一个地方保存客户端信息。
cookie保存在客户端 而session保存在服务器端
我们打开github官网 登录
然后关闭该网页
再次打开这个网站
我们发现没有让我们再次登录 因为我们用户的信息 通过cookie 保存在了客户端 所以 我们再次登录网站会识别cookie
我们再换个网站举例 比如知乎
登录知乎后
复制热榜中全站的第一个标题
查看网页源代码
源代码中有该标题 说明当前页面就是这个源代码通过浏览器渲染出来的
我们学cookie 的用处
一 模拟登陆
二 反爬
#我们学cookie 的用处
#一 模拟登陆
import requests
url='https://www.zhihu.com/hot'
res=requests.get(url)
print(res.text)
#二 反爬
如果源码中有这些数据 则证明我们登录成功了
run一下
很明显没有成功
可以添加请求头
#我们学cookie 的用处
#一 模拟登陆
import requests
import random
headers_list = [
{'User-Agent': 'Mozilla/5.0.html (Windows NT 6.1; WOW64) '},
{'User-Agent': 'AppleWebKit/537.36 (KHTML, like Gecko)'},
{'User-Agent': 'Chrome/39.0.html.2171.71 Safari/537.36'},
{'User-Agent': 'Mozilla/5.0.html (X11; Linux x86_64) '},
{'User-Agent': 'AppleWebKit/537.11 (KHTML, like Gecko) '},
{'User-Agent': 'Chrome/23.0.html.1271.64 Safari/537.11'},
{'User-Agent': 'Mozilla/5.0.html (Windows; U; Windows NT 6.1; en-US)'},
{'User-Agent': 'AppleWebKit/534.16 (KHTML, like Gecko)'},
{'User-Agent': ' Chrome/10.0.html.648.133 Safari/534.16'}]
headers=random.choice(headers_list)
url='https://www.zhihu.com/hot'
res=requests.get(url,headers=headers)
print(res.text)
#二 反爬
我们拿到的这个文本数据处于一个没有登录的状态 当你输入www.zhihu.com 它会临时重定向一个页面让你登录 知乎跟其他如 csdn 简书 不同 不登录是没法看到首页的
我们再次回到已经登录好的知乎首页 检查 network 中重新加载 点击 左上角 hot
#我们学cookie 的用处
#一 模拟登陆
import requests
headers = {'User-Agent': 'Mozilla/5.0.html (Windows NT 6.1; WOW64) ','cookie':'_xsrf=1SMkDEbBof93pTCRd5MmPz8cmmOuAsaU; _zap=3a8fd847-c5d4-45cf-84a3-24d508f580f6; _ga=GA1.2.2058930090.1594280819; d_c0="AICeuVa2jBGPTuvzpsC3VFkq3TulCqxCfNQ=|1594280816"; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1594280819,1594472555,1594901189; _gid=GA1.2.1424998048.1594901190; SESSIONID=N8kg63Tsh3lZGMF6vI5Fc4gl1B5dIOcyaU6UmrlNRqC; JOID=UVETAkt1itLQrDzMQ3dDxdpur0pXMb2-tpkFlzces7GN6nKAerbAxI2lOcRFiilFl3XWVmgBvZbqyLeAR5S01Rk=; osd=Vl0SBE9yhtPWqDvAQnFHwtZvqU5QPby4sp4JljEatL2M7HaHdrfGwIqpOMJBjSVEkXHRWmkHuZHmybGEQJi10x0=; capsion_ticket="2|1:0|10:1594901205|14:capsion_ticket|44:YWM2MTNmYTg1ODIzNDQwMzhiNTAwODIwNjc0NzRjZWQ=|a77fc810e5b1b898bb505e067a80d273d6f10bc1e3d44581314a9a6d621a78a8"; z_c0="2|1:0|10:1594901209|4:z_c0|92:Mi4xRjdYeENBQUFBQUFBZ0o2NVZyYU1FU1lBQUFCZ0FsVk4yWkQ5WHdBbzV5TkZwYUs4a0RpNWdRUms2Yy1OQlRkaER3|3e67794db7e5f5ec768144d12fdac5ddf9be6d575cf0da3081bd59c5fd132558"; Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49=1594901211; tst=h; tshl=; KLBRSID=b33d76655747159914ef8c32323d16fd|1594901257|1594901188'}
url='https://www.zhihu.com/hot'
res=requests.get(url,headers=headers)
print(res.text)
你发现和刚才的明显不一样 了
二 反爬
先打开一个网站12306
这个流程是先查票查完票再登录
我们首先得拿到一个车次信息
那么我们要拿到车次信息需要拿到 需要拿到这个url吗(其实拿取车次信息跟这个url是没有联系的)
#二 反爬
import requests
url='https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
res=requests.get(url)
print(res.text)
run一下
而需要获得到的数据(车次)明显不是在这个url中
页面是由这个源代码通过浏览器渲染出来的 所以我们车次的数据在网页源代码中都有
在当前页面查看网页源代码
输入车次G2195 源代码中却没有这个数据
我们知道页面是由这个源代码通过浏览器渲染出来的
----那么为什么网页中有的数据为什么网页的源代码中没有呢?
----那么这些数据我们该如何找出来呢?
当我们的从12306发起一个请求给 服务器时 服务器会把数据返回给客户端(浏览器) 但是有的时候会有出现特殊情况 当我们的客户端对服务器多次发起请求的时候 我们就没法确定每一次传输的内容是什么
一般情况 我们可以通过网络源码 可以看服务器给浏览器传递了什么数据 但是发起多次请求时就无法确定了
因为源码的url 它只能接受源码的这些数据
再有的数据就不会显示在源码当中了 从这个url也就没法查看到了
所以我我们发现在网页中有的数据在网页源代码中没有 而且我们用这个url
https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc 发起请求拿到的数据也是不对的 那么有可能就是服务器多次传输
而且我们会发现一个细节 这个车次列表是本来就没有的 当我们点击查询过后 才出现了车次列表的
我们尝试用抓包工具找一下
google浏览器打开检查 network 首先要刷新浏览器页面
我们发现刷新过后这个页面又变成了最原始的样子
此时先清空 clear
点击clear后 再点击查询
那么就会出现
点击query(查询的意思)
在preview中
这个数据就靠谱多了
而result中0到11 这12行
我们仔细观察
其中有预定
且在第0行中找到了车次列表中的第一行
那么这个数据就对得上了
那么拿去这个数据 则需要 query对应的url
#二 反爬
import requests
#为什么网页中有的数据为什么源代码中没有呢
#那么这些数据我们该如何找出来
url='https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2020-08-12&leftTicketDTO.from_station=CDW&leftTicketDTO.to_station=CSQ&purpose_codes=ADULT'
res=requests.get(url)
print(res.content.decode('utf-8'))
run后结果是
网络可能存在问题 找了半天没有车次数据 说明被反爬了
我们在headers中加入user-agent
#二 反爬
import requests
#为什么网页中有的数据为什么源代码中没有呢
#那么这些数据我们该如何找出来
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'}
url='https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2020-08-12&leftTicketDTO.from_station=CDW&leftTicketDTO.to_station=CSQ&purpose_codes=ADULT'
res=requests.get(url,headers=headers)
print(res.content.decode('utf-8'))
然而结果还是被反爬了
我们要的html应该是
这个一点都不一样
那么我们把这个cookie加上试试 当然此处的Cookie 首字母大写了 (上次知乎的是小写的cookie) 这个的大小写根据网站的变化来定
#二 反爬
import requests
#为什么网页中有的数据为什么源代码中没有呢
#那么这些数据我们该如何找出来
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36','Cookie: _uab_collina=159713069371831632863661; JSESSIONID=9E5B8DDC57337C88476F6D365F4B3BA8; RAIL_EXPIRATION=1597462110322; RAIL_DEVICEID=BojZvbgslGHQgGQCbXBFX5gZFgRKGwnavcD2Ce9WFqUaTaXwQv7gPq-h2z-SRz7I8RKKBHUidE-C06l5kbN3a-y2iEFrxTAnUgacvy0y7tMC5_txxv9wH30IDoYCT6bPu9z7EULYfgPHiduDWyLfdRGT4fWmcn5N; BIGipServerpool_passport=351076874.50215.0000; route=6f50b51faa11b987e576cdb301e545c4; BIGipServerotn=351273482.38945.0000; _jc_save_fromStation=%u6210%u90FD%2CCDW; _jc_save_toStation=%u957F%u6C99%2CCSQ; _jc_save_toDate=2020-08-11; _jc_save_fromDate=2020-08-12; _jc_save_wfdc_flag=dc'}
url='https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2020-08-12&leftTicketDTO.from_station=CDW&leftTicketDTO.to_station=CSQ&purpose_codes=ADULT'
res=requests.get(url,headers=headers)
print(res.content.decode('utf-8'))
{"httpstatus":200,"data":{"result":["nQD5R6eJKtDrnHLa3pfJRVmQTOpnjVfReq3FyK3I2TZ2AChjacE6%2BPFGfUjiTr4%2Bb1c3kA8GC6%2BA%0AmhnSmm82ZJ3t%2FJQRUpztOne%2BX21t%2Btv41RkSPp76P28fyiytRLNrkA4RhNTMsToTopYY9ZN4qesc%0A6medUEyZ9FzK6zfleSAXXDO%2BpIGJmXnks9RsbFsF3TbLbXV1T0YXGBMKLC7HyyQD5uTuXhR3J%2BAq%0Ak2Fyo%2F2G5TWeWSExq0YAuur7po6xHSakYICB%2Flp8cPnaF0%2FBwvLJViZ4UYaH8q3ipivj6iuhskqi%0A|预订|76000G218301|G2183|ICW|CWQ|ICW|CWQ|16:30|23:35|07:05|N|8S7r8rY5keqHYWuVGngN1uNifxX4BkJNkRTzv9z%2BXWdmC1U7|20200812|3|W3|01|12|1|0||||||无|||||无|无|||O0P0M0|OPM|1|1||O057850000P107500000M095200000||||||1|0"],"flag":"1","map":{"ICW":"成都东","CWQ":"长沙南"}},"messages":"","status":true}
类似的反爬比如百度 多次请求百度 会弹出百度安全验证 当你把cookie加上去后就依然能继续请求了
其实headers中 尽可能多加写 爬取成功几率会增加的 user-agent (用户代理) cookie refer 在加上的其实也见得是加上就能爬取到了 基本上就是这3个
session :通过在服务端记录的信息确定用户身份 这里这个session就指的是会话
这个session 不是web中的session 是请求模块中的session
保持会话
session是指从我们打开一个网站开始至我们关闭浏览器一系列的请求过程。比如我们打开淘宝网站,淘宝网站的服务器就会为我们创建并保存一个会话对象,会话对象里有用户的一些信息,比如我们登陆之后,会话中就保存着我们的账号信息。会话有一定的生命周期,当我们长时间(超过会话有效期)没有访问该网站或者关闭浏览器,服务器就会删掉该会话对象。 cookies是指网站为了辨别用户身份,进行会话跟踪而储存在本地终端的数据,cookies一般再电脑中的文件里以文本形式储存。
我们可以拿12306这个网站来做个案例
12306是2012年推出的实名制买票网站 每天点击量有10亿之多 尤其是过年放假
所以上面 的东西确实可以去降低服务器的压力
session 保持会话
攻克图片验证码
{'result_message': "验证码校验成功",'result_code': "4"}
只要控制台打印这个 就代表验证码校验成功了
我们会发现输入账号 错误的密码 输入正确的验证码比错误的明显多了写东西 最主要的变化是多有了login请求
可以发现这个网站一定是先会去校验的你的验证码 你的验证码校验成功之后才会 才会请求你的账号密码 你的验证码校验失败 网站是不会请求你的账号和密码的
#攻克图片验证码
#{‘result_message’: “验证码校验成功”,‘result_code’: “4”}
#只要控制台打印这个 就代表验证码校验成功了
#1. 目标url
#2.拿到验证码图片
#3.判断哪些图片是正确的
就是这个url 这是一个get请求 但是我们得用post请求 因为还得要提交下数据 图片验证码的坐标
我们仅需这个url前面的https://kyfw.12306.cn/passport/captcha/captcha-check 就够了
后面还有很多参数 参数都在下面的Query String Parameters
也就是最后一个参数时间戳不用提交 rand 和 login_site 是固定 的 关键是参数坐标值answer 来找到哪个是该找的图片
而且它用的是get请求 我们就不用了 我们用post请求
先复制上面的url 在用pycharm进行操作
我的操作有点相反 是前面第一次是验证码输入正确的(有login请求) 后面几次输入失败的 是没有login请求的
# session 保持会话
# 攻克图片验证码
# {'result_message': "验证码校验成功",'result_code': "4"}
# 只要控制台打印这个 就代表验证码校验成功了
import requests
import random (当然这个是完全可以不用的 只是多了一个在请求头列表中随机获取请求头操作而已)
headers_list = [{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'}]
headers=random.choice(headers_list)
#1. 目标url
def login():
# 数据 Query String Parameters 中的3个参数
# 别把data写成date了..
data={'answer': '118,126,8,133','rand': 'sjrand','login_site': 'E'}
response=requests.post('https://kyfw.12306.cn/passport/captcha/captcha-check',data=data,headers=headers)
print(response)
#2.拿到验证码图片
#3.判断哪些图片是正确的
login()
<Response [200]>
直接打印出来是个响应对象 200
所以得print(response.text)
# session 保持会话
# 攻克图片验证码
# {'result_message': "验证码校验成功",'result_code': "4"}
# 只要控制台打印这个 就代表验证码校验成功了
import requests
import random
headers_list = [{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'}]
headers=random.choice(headers_list)
#1. 目标url
def login():
# 数据 Query String Parameters 中的3个参数
# 别把data写成date了..
data={'answer': '118,126,8,133','rand': 'sjrand','login_site': 'E'}
response=requests.post('https://kyfw.12306.cn/passport/captcha/captcha-check',data=data,headers=headers)
print(response.text)
#2.拿到验证码图片
#3.判断哪些图片是正确的
login()
/**/jQuery19108110694752761256_1597840679267({"result_message":"验证码校验失败,信息为空","result_code":"8"});
然后是拿到验证码的图片
拿到图片的url
创建新的text.py文件
这个url也太多了
而随便一张百度的图片
它url的长度明显比12306网站上的要短很多的
原因是该网站在这里做了一个base64的处理
导入base64模块 (python自带的模块)
用这个模块中b64decode的这样一个方法解决
import base64
url='data:image/jpg;base64,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'
img_data=base64.b64decode(url)
fn=open('code.png','wb')
fn.write(img_data)
fn.close()
run一下报了这个错误
binascii.Error: Incorrect padding
binascii.错误:填充不正确
原因 是这些数据信息的是不需要的
把它删掉就好了
那么删掉后再次就没有什么错误发生了
其实类似这种情况 你拿数据拿不到的时候就尝试把url前面的data:image/jpg;base64删掉就好
但是上面的那种写法有些臃肿 不符合OTC 不建议用
那么这张图片是怎么出来呢
复制这个request url 打开看看是不是图片链接
https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&1597848725389&callback=jQuery19103491748461618709_1597848712815&_=1597848712817
打开链接后是一堆除了下面的文字以外 你都看不懂的代码
而且下面还有一个
captcha-image64?login_site=E&module=login&rand=sjr…
开头的这个玩意 再复制它的 request url 打开看看
果然跟上面的一样的效果 是一堆看不懂的代码 但是两者的request url 是有些小地方数字不一样
'https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&1597848719229&callback=jQuery19103491748461618709_1597848712815&_=1597848712816'
'https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&1597848725389&callback=jQuery19103491748461618709_1597848712815&_=1597848712817'
# 两条url的相同部分
'https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand'
打开相同部分
只需将相同url中的 64 去掉 就获得了图片验证码的链接
https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand
我们再回到session.py中
# session 保持会话
# 攻克图片验证码
# {'result_message': "验证码校验成功",'result_code': "4"}
# 只要控制台打印这个 就代表验证码校验成功了
import requests
import random
headers_list = [{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'}]
headers=random.choice(headers_list)
#1. 目标url
def login():
# 2.拿到验证码图片 传入刚才获得的图片验证码url
pic_response=requests.get('https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand')
codeimage=pic_response.content
fn=open('codeee.png','wb')
fn.write(codeimage)
fn.close()
# 数据 Query String Parameters 中的3个参数
# 别把data写成date了..
data={'answer': '118,126,8,133','rand': 'sjrand','login_site': 'E'}
response=requests.post('https://kyfw.12306.cn/passport/captcha/captcha-check',data=data,headers=headers)
#print(response.text)
#3.判断哪些图片是正确的
login()
# session 保持会话
# 攻克图片验证码
# {'result_message': "验证码校验成功",'result_code': "4"}
# 只要控制台打印这个 就代表验证码校验成功了
import requests
import random
headers_list = [{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'}]
headers=random.choice(headers_list)
#1. 目标url
def login():
# 2.拿到验证码图片 传入刚才获得的图片验证码url
pic_response=requests.get('https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand')
codeimage=pic_response.content
fn=open('codeee.png','wb')
fn.write(codeimage)
fn.close()
# 3.判断哪些图片是正确的
codeStr=input('请输入验证码坐标:')
# 数据 Query String Parameters 中的3个参数
# 别把data写成date了..
data={'answer': codeStr,'rand': 'sjrand','login_site': 'E'}
response=requests.post('https://kyfw.12306.cn/passport/captcha/captcha-check',data=data,headers=headers)
print(response.text)
login()
而且重复运行我们的codeee.png是会变化的
run一下 再打开codeee.png 从左上角开始截图
回车后还是不对
怎么回事呢?、
我向一个网站发起一个 请求 那么要保持这个会话状态去做其他的一些事 也就是我们在对图片进行一些操作的时候依然还保持会话
req=requests.session()
那么就用req发起请求
那么得将下面的request 改写为req
# 2.拿到验证码图片 传入刚才获得的图片验证码url
pic_response=req.get('https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand')
codeimage=pic_response.content
fn=open('codeee.png','wb')
fn.write(codeimage)
fn.close()
# 3.判断哪些图片是正确的
codeStr=input('请输入验证码坐标:')
# 数据 Query String Parameters 中的3个参数
# 别把data写成date了..
data={'answer': codeStr,'rand': 'sjrand','login_site': 'E'}
response=req.post('https://kyfw.12306.cn/passport/captcha/captcha-check',data=data,headers=headers)
# print(response.text)
还是重复的截图操作
其实这个就是手动添加图片坐标 相当与登录时的点击 只要这个坐标在该正确图片内就行
请输入验证码坐标:187,63,255,54
{"result_message":"验证码校验成功","result_code":"4"}
请输入验证码坐标:187,63,255,54 这个格式与 下图answer中数据点的格式是一样的
整个案例最重要的3个点
第一个图片url是通过比较 删掉-image64的64 获得的
第二个 网页中的请求是get请求 但是我们得用post请求 因为还得要提交下数据 图片验证码的坐标
第三个 在12306中操作图片验证码 找坐标的时候 要在保持会话的状态下进行 (req=requests.session()然后就是把原来的request 改写成我们自己定义的变量req)
当客户端浏览器第一次请求服务器时,服务器会再response中设置一个Set-Cookies的字段,用来标记用户的身份,客户端浏览器会把cookies保存起来,cookies中保存的有Session的id信息。当客户端浏览器再次请求该网站时,会把Cookies放在请求头中一起提交给服务器,服务器检查该Cookies即可找到对应的会话是什么,再通过判断会话来辨认用户的状态。 当我们成功登陆网站时,网站会告诉客户端应该设置哪些Cookies信息,以保持登陆状态。如果客户端浏览器传给服务器的cookies无效或者会话过期,可能就会收到错误的响应或者跳转到登陆页面重新登陆。
import random
def __init__(self):
headers_list = [
{'User-Agent': 'Mozilla/5.0.html (Windows NT 6.1; WOW64) '},
{'User-Agent': 'AppleWebKit/537.36 (KHTML, like Gecko)'},
{'User-Agent': 'Chrome/39.0.html.2171.71 Safari/537.36'},
{'User-Agent': 'Mozilla/5.0.html (X11; Linux x86_64) '},
{'User-Agent': 'AppleWebKit/537.11 (KHTML, like Gecko) '},
{'User-Agent': 'Chrome/23.0.html.1271.64 Safari/537.11'},
{'User-Agent': 'Mozilla/5.0.html (Windows; U; Windows NT 6.1; en-US)'},
{'User-Agent': 'AppleWebKit/534.16 (KHTML, like Gecko)'},
{'User-Agent': ' Chrome/10.0.html.648.133 Safari/534.16'}]
self.headers = random.choice(headers_list) 随机选择请求头列表中的请求头
self.baseurl = 'https://tieba.baidu.com/f?'
什么是SSL证书?
• SSL证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本。因为配置在服务器上,也称为SSL服务器证书。SSL 证书就是遵守 SSL协议,由受信任的数字证书颁发机构CA,在验证服务器身份后颁发,具有服务器身份验证和数据传输加密功能
比如我们有时候工作时就得访问不信任的ssl证书来干点事
https://inv-veri.chinatax.gov.cn/
import requests
url='https://inv-veri.chinatax.gov.cn/'
res=requests.get(url)
print(res.text)
不是代码有问题 而是这个网址是浏览器证书风险的 (不信任的sll证书)
而且就算你打开了 https://inv-veri.chinatax.gov.cn/
用360浏览器 但是pycharm还是访问不到的.
import requests
url='https://inv-veri.chinatax.gov.cn/'
res=requests.get(url,verify=False) verify就是验证 核实的意思 而verify=False就是不需要再核实鉴别的意思了
print(res.content.decode('utf-8'))
run后这样就可以访问到了 这个网页 html的文件
import requests
#发起请求
response=requests.get('https://www.baidu.com/?tn=88093251_34_hao_pg')
#获取响应对象
print(response)
<Response [200]> 只要是这个< > 尖括号 它就是个对象
print(response,type(response))
<Response [200]> <class 'requests.models.Response'>
import requests
#https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD
headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
wd={'wd':'中国'}
#发起请求
response=requests.get('https://www.baidu.com/s?',params=wd,headers=headers)
#获取响应对象
print(response)
<Response [200]>
import requests
#https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD
headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
wd={'wd':'中国'}
#发起请求
response=requests.get('https://www.baidu.com/s?',params=wd,headers=headers)
#获取响应对象
print(response.text)
若是
print(type(response.text))
<class 'str'>
import requests
#https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD
headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
wd={'wd':'中国'}
#发起请求
response=requests.get('https://www.baidu.com/s?',params=wd,headers=headers)
#获取响应对象
# print(type(response.text))
print(response.content,type(response.content))
<class 'bytes'>
假如你这个数据 是一个音乐 图片 视频 那就要返回一个二进制字节流数据就用(response.content )
假如 数据是一个网页源码 html文件 就得返回一个字符串类型的数就用(response.text)
response.text
也就是说可以这样动态的添加网址(图片二进制数据也是可以)
response=requests.get(‘https://www.baidu.com/s?’,params=wd,headers=headers)
也就是上图中response 是一个网页源码 就是一个str类型 直接可以用
用response.content也可以 就是得response.content.decode( )
不加.decode()
字节流数据 bytes b’开头 获取到的网页源码就成了乱码
我们打开一个网址
https://qq.yh31.com/ql/jy/99120.html
import requests
#https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD
headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
wd={'wd':'中国'}
#发起请求
response=requests.get('https://www.baidu.com/s?',params=wd,headers=headers)
#获取响应对象
# print(type(response.text))
# print(response.content,type(response.content)) 字节流数据 二进制
# print(response.url) #返回请求的url
res=requests.get('https://qq.yh31.com/ql/jy/99120.html')
print(res.text)
res=requests.get('https://qq.yh31.com/ql/jy/99120.html')
print(res.content)
我们发现还是看不懂的
这样结果内容才与图片页面的源码一样
且此时的这行代码中
print(res.content.decode('utf-8'))
content 是一个方法 并不是变量
我们来说一下为何会产生这个情况
首先text 返回的是一个字符串这没问题 然后呢content返回的是一个字节流数据
那上图中我们加上了.decode 返回来是一个字符串 并且还把乱码问题解决了
因为 res.text虽然看似一步的操作 其实是先用res.content的方法拿到数据 然后再用requests 的其他模块去解码 因为是requests库自己解码所以 可能出现错误 (没有解对) 所以用text方法其实已经就调用了content方法
不如我们直接用content方法手动解码
所以这一步print(type(res.content.decode('utf-8')))
是获取数据源代码最保险的一种方式
import requests
#https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD
headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}
wd={'wd':'中国'}
#发起请求
response=requests.get('https://www.baidu.com/s?',params=wd,headers=headers)
#获取响应对象
# print(type(response.text))
# print(response.content,type(response.content)) 字节流数据 二进制
# print(response.url) #返回请求的url
res=requests.get('https://qq.yh31.com/ql/jy/99120.html')
res.encoding='utf-8'
# print(type(res.content.decode('utf-8')))
print(res.text)
结果也是这个图片的网页源代码 不会出现乱码问题 当然还是建议用第一种
那res.text.decode(‘utf-8’) 不就也行
AttributeError: ‘str’ object has no attribute ‘decode’
AttributeError:“str”对象没有属性“decode”
• response.text 返回unicode格式的数据(str)
• response.content 返回字节流数据(二进制)
• response.content.decode(‘utf-8’) 手动进行解码
• response.url 返回url
• response.encoding=‘编码’
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/6 21:35
# @Author : Lonegly
# @File : requests模块发送Post请求;额.py
# @Software: PyCharm
import requests
import json
key=input('请输入内容:')
data={
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15880623642174',
'sign': 'c6c2e897040e6cbde00cd04589e71d4e',
'ts': '1588062364217',
'bv': '42160534cfa82a6884077598362bbc9d',
'doctype': 'json',
'version': '2.1',
'keyfrom':'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
res=requests.post(url,data=data,headers=headers)
res.encoding='utf-8'
html=res.text
r_dict=json.loads(html)
r=r_dict['translateResult'][0][0]['tgt']
print(r)
#后面的操作前面 提及 r=r_dict['translateResult'][0][0]['tgt']
请输入内容:好吗好的呀
Good good ah
提高自己
当你的技术提高以后 你需要看一些更好的设计模式以及开发思想 思路
还比如如果公司给你一个框架的源代码3000行 给你3天看完 这时候这种能力就会很重要
打开github官网
直接搜索requests
或者是
复制
不行的话还是老老实实用上面的方法
下载它源码的压缩包
下载完后 解压 再用pycharm打开它
前两个先不用看 docs 文档 ext扩展 requests 是核心的文件夹 是我们主要看的
tests 测试的一些东西
JSON 字符串
JSON 中的字符串必须用双引号包围。
实例
{ "name":"John" }
数据提取
什么是数据提取?
简单的来说,数据提取就是从相应中获取我们想要的数据的过程
数据分类
非结构化数据:HTML
处理方法:正则表达式、xpath
结构化数据:json、xml
处理方法:转化为Python数据类型
html 就比如百度页面的源代码 这个结构你看不出来
json
xml 以后在介绍
数据提取之json
由于把json数据转化为python内建数据类型很简单,所以爬虫中,如果我们能够找到返回json数据的URL,就会尽量使用这种URL
JSON是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。
使用json注意点
• json中的字符串都是双引号
只要是loads dumps (带有s的) 这个数据转化就和字符串有关系
j 变p load(s)
**并且 json.dump()这个方法 必须接收两个参数 只能写入文件
json.load()方法只能接收一个参数 只能读取文件 **
具体可以看看奇怪的现象
import json
s='json'
print(s,type(s))#json
#python数据类型 --> json类型的字符串
print(json.dumps(s),type(json.dumps(s)))
json <class 'str'>
"json" <class 'str'>
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
json.dump(s,open('json.txt','w')) 传入s 就是上面的字符串 然后用open()写入文件
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
json.dump(s,open('json.txt','w'))
# json文件字符串--->python数据类型
p=json.load(open('json.txt','r')) r只读
print(p) #json
json
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
json.dump(s,open('json.txt','w'))
d=open('json.txt','r')
print(d)
# json文件字符串--->python数据类型
# p=json.load(open('json.txt','r'))
# print(p) 没有办法能和这个一样打印出
<_io.TextIOWrapper name='json.txt' mode='r' encoding='cp936'>
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
json.dump(s,open('json.txt','w'))
d=json.dump(open('json.txt','r'))
print(d)
# json文件字符串--->python数据类型
# p=json.load(open('json.txt','r'))
# print(p)
TypeError: dump() missing 1 required positional argument: 'fp'
TypeError:dump()缺少1个必需的位置参数:“fp”
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
json.dump(s,open('json.txt','w'))
d=json.dump(s,open('json.txt','r'))
print(d)
# json文件字符串--->python数据类型
# p=json.load(open('json.txt','r'))
# print(p)
io.UnsupportedOperation: not writable
不支持操作:不可写
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
json.dump(s,open('json.txt','w'))
d=json.load(s,open('json.txt','r'))
print(d)
# json文件字符串--->python数据类型
# p=json.load(open('json.txt','r'))
# print(p)
TypeError: load() takes 1 positional argument but 2 were given
TypeError:load()接受1个位置参数,但给出了2个
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
json.dump(s,open('json.txt','w'))
d=json.load(open('json.txt','r'))
print(d)
# json文件字符串--->python数据类型
p=json.load(open('json.txt','r'))
print(p)
json
json
import json
s='json'
# print(s,type(s))#json
#python数据类型 --> json类型的字符串
# print(json.dumps(s),type(json.dumps(s)))#"json"
# python数据类型--->json文件字符串
# json.dump(s,open('json.txt','w'))
d=json.load(s,open('json.txt','w'))
print(d)
# json文件字符串--->python数据类型
# p=json.load(open('json.txt','r'))
# print(p)
TypeError: load() takes 1 positional argument but 2 were given
TypeError:load()接受1个位置参数,但给出了2个
可以看出dump只能写入文件不能读 而load只能读
其原因应该是json.dump()这个方法 必须接收两个参数 json.load()方法只能接收一个参数