爬虫请求模块
python内置模块
1. urllib.request 模块
举例
# 爬取图片
import requests
url = 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2374990454,1868544642&fm=11&gp=0.jpg'
req = requests.get(url)
# 两种方式读写图片二进制文本
#
#fn = open('code.png','wb')
#
#fn.write(req.content) # 二进制数据
#
#fn.close()
with open('code.png','wb') as fn:
f.write(req.content)
使用内置模块urllib
from urllib import request
url = 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2374990454,1868544642&fm=11&gp=0.jpg'
request.urlretrieve(url,'code3.png')
· 版本
python2: urllib2 urllib
python3: 把urllib和urllib2合并为urllib.request
· 常用的方法
urllib.request.urlopen(url) 向网站发起一个请求并获取响应
字节流 = response.read()
字符串 = response.read().decode(‘utf-8’)
import urllib.request
# 向某个未反爬的网站发起一个请求 得到一个响应结果 并用一个变量接收
response = urllib.request.urlopen('http://qq.yh31.com/zjbq/2920180.html')
# 从响应对象中获取数据 read()函数读取数据
# print(response) # 得到一个响应对象
# html = response.read() # 获取数据是一个二进制数据,字节流bytes,需要解码操作decode('utf-8')
html = response.read().decode('utf-8') # 获取数据是一个字符串流
print(html,type(html)) # 显示了源代码
· urllib.requser.Resquest(url=‘网址’,headers=‘字典UA’)
需要注意urlopen()不支持重构User-Agent
import urllib.request
# 请求反爬的网站如百度的数据(网页源码)
url = 'www.baidu.com'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
# 1. 创建请求对象(构建User-Agent)
response = urllib.request,Request(url,headers=headers)
# 2. 获取响应对象(urlopen())
res = urllib.request.urlopen(response)
# 3. 读取响应对象的内容
html = res.read().decode('utf-8')
print(html) # 获取网页源码
print(res.getcode()) # 获取状态码
print(res.geturl()) # 获取实际请求的网址
# 如果不添加headers
# 向百度网站发起一个请求 得到一个响应结果 并用一个变量接收
# response = urllib.request.urlopen('http://www.baidu.com')
#response = urllib.request.urlopen('http://www.baidu.com')
# 从响应对象中获取数据 read()函数读取数据
# print(response)
#html = response.read().decode('utf-8')
# print(html,type(html)) # 做了反爬,显示不了全部源网页源代码
· 响应对象的方法
res.read() 读取服务器响应的内容,返回的是一个字节流,需要decode(‘utf-8’)解码获得字符串
res.getcode() 返回HTTP的响应状态码
res.geturl() 返回实际数据的URL(防止重定向问题)
2. urllib.parse 模块
· 常用方法
urllib.parse.urlencode(字典)
import urllib.parse
# 在百度搜索框中输入‘海贼王’后,复制url
# 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
baseurl = 'https://www.baidu.com/s?'
content = input('请输入你想输入的内容:')
r = {'wd':content}
content = urllib.parse.urlencode(r)
# 拼接url
url = baseurl + content
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
# 创建请求对象
req = urllib.request.Request(url,headers=headers)
# 获取响应对象
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')
# 保存文件
with open('content.html','w',encoding='utf-8') as f:
f.write(html)
urllib.parse.quote(字符串)
import urllib.parse
# url = 'https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B'
key = input('请输入内容:')
baseurl = 'https://www.baidu.com/s?wd='
r = urllib.parse.quote(key) # 将字符串转化为ascii码
url = baseurl + r
print(url) # 'https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B'
百度贴吧练习一
需求:1.输入要爬取贴吧的主题类 ;2.输入爬取的起始页和终止页;3. 把每页的内容保存到本地html文件
# 分析
# 第一页 url = 'https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&ie=utf-8&pn=0'
# 第二页 url = 'https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&ie=utf-8&pn=50'
# 第三页 url = 'https://tieba.baidu.com/f?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&ie=utf-8&pn=100'
# pn = (当前页数-1)* 50 kw 是贴吧的主题
import urllib.request
import urllib.parse
import random
# 随机获取一个User-Agent
headers_list = [{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'},{'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'}]
headers = random.choice(headers_list)
# print(headers)
name = input('请输入贴吧名:')
start = int(input('请输入起始页:'))
end = int(input('请输入终止页:'))
# 对贴吧名进行编码
kw = {'kw':name}
kw = urllib.parse.urlencode(kw)
# 开始拼接url 发起请求获取响应,并保存文件
for i in range(start,end+1):
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) + '页.html'
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 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}
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('请输入终止页:'))
# 对贴吧名进行编码
kw = {'kw':name}
kw = urllib.parse.urlencode(kw)
for i in range(start,end+1):
pn = (i-1) * 50
baseurl = 'https://tieba.baidu.com/f?'
url = baseurl + kw + '&pn=' + str(pn)
html = readPage(url)
# 写入文件
filename = '第' + str(i) + '页.html'
writePage(filename,html)
if __name__ == '__main__':
main()
百度贴吧练习三
# 将上述需求写成类
import urllib.request
import urllib.parse
class BaiduSpider:
def __init__(self):
# 常用的不变的放入init方法
self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}
self.baseurl = 'https://tieba.baidu.com/f?'
def readPage(self,url):
req = urllib.request.Request(url,headers=self.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('请输入终止页:'))
# 对贴吧名进行编码
kw = {'kw':name}
kw = urllib.parse.urlencode(kw)
for i in range(start,end+1):
pn = (i-1) * 50
url = self.baseurl + kw + '&pn=' + str(pn)
html = self.readPage(url)
# 写入文件
filename = '第' + str(i) + '页.html'
self.writePage(filename,html)
if __name__ == '__main__':
# 创建实例
spider = BaiduSpider()
spider.main()
3. 请求方式
· get :查询参数直接在URL地址中显示
· post:在Request方法中添加data参数
urllib.request.Request(url,data=data,headers=headers)
data: 表单数据以bytes类型提交,不能是str
练习:
需求:制作有道翻译小软件(post)
import urllib.request
import urllib.parse
import json
# 输入翻译的内容
key = input('请输入要翻译的内容:')
# 把提交的form表单数据转换成bytes类型的数据, form表单位于translate_o中headers中,写成字典
data = {
'i': key,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '16016974561177',
'sign': '3f44ca0ab29ee37fa99f4ccf68295ee0',
'lts': '1601697456117',
'bv': '52dd8074f15d3797000a252ed2659a35',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
data = urllib.parse.urlencode(data) # 字典字符串转换
# 把data数据转换成字节流数据
data = bytes(data,'utf-8')
# 发起请求提交数据,获取响应
# url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
# url需要去掉_o
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}
req = urllib.request.Request(url,data=data,headers=headers)
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')
# print(html,type(html))
# json字符串 {"type":"ZH_CN2EN","errorCode":0,"elapsedTime":1,"translateResult":[[{"src":"年龄","tgt":"age"}]]}
# "translateResult":[[{"src":"年龄","tgt":"age"}]]
# [[{"src":"年龄","tgt":"age"}]]
# [{"src":"年龄","tgt":"age"}]
# {"src":"年龄","tgt":"age"}
# 把json类型的字符串转换从字典
r_dict = json.loads(html)
r = r_dict['translateResult'] # [[{"src":"年龄","tgt":"age"}]]
content = r[0][0]['tgt']
print(content)
4. requests模块
· 安装
pip install requests
在开发工具中安装:
pip install requests -i https://pypi.douban.com/simple
· 常用方法
request.get()
· 响应对象response的方法
response.text 返回unicode格式的数据(str),拿到数据字节流,解码后得到的字符串,可能会出轮吗,可以手动编码
response.content 返回字节流数据(二进制)
response.content.decode(‘utf-8’) 手动进行解码
response.url 返回url
response.encode() = ‘编码’
import requests
# https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd=%E4%B8%AD%E5%9B%BD
# url = 'http://www.baidu.com/'
url = 'http://www.baidu.com/s?'
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}
wd = {'wd': '中国'} # 动态提交数据
# 发起请求
# response = requests.get(url,headers=headers)
response = requests.get(url,params=wd,headers=headers)
# 获取响应对象
print(response) # <Response: [200]> 对象 状态码
print(response.text,type(response.text)) # 返回str
print(type(response.content),response.content) # 返回字节流bytes
print(response.url) # 返回请求url
import requests
res = requests.get('http://qq.yh31.com/zjbq/2920180.html')
# print(res.text) # 有乱码
print(res.content.decode('utf-8')) # 正常输出源码,无乱码
import requests
res = requests.get('http://qq.yh31.com/zjbq/2920180.html')
res.encoding = 'utf-8'
print(res.text) # 无乱码
· request.post 请求
import requests
import json
key = input('请输入要翻译的内容')
data = {
'i': key,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '16016974561177',
'sign': '3f44ca0ab29ee37fa99f4ccf68295ee0',
'lts': '1601697456117',
'bv': '52dd8074f15d3797000a252ed2659a35',
'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 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}
res = requests.post(url,data=data,headers=headers)
res.encoding = 'utf-8'
html = res.text
r_dict = json.loads(html)
# print(r_dict)
r = r_dict['translateResult'] # [[{"src":"年龄","tgt":"age"}]]
content = r[0][0]['tgt']
print(content)
· request设置代理
http://httpbin.org/user-agent
http://httpbin.org/ip
代理网站
西刺免费代理IP:http://www.xicidaili.com/
快代理:http://www.kuaidaili.com/
代理云:http://www.dailiyun.com/
import requests
# 免费代理ip
proxy = { 'http': '115.218.213.220.9000'
}
url = 'http://httpbin.org/ip'
res = requests.get(url,proxies=proxy)
print(res.text) # 报错说明ip被使用过
· cookie
cookie :通过在客户端记录的信息确定用户身份
HTTP是一种无连接协议,客户端和服务器交互仅仅限于 请求/响应过程,结束后断开,下一次请求时,服务器会认为是一个新的客户端,为了维护他们之间的连接,让服务器知道这是前一个用户发起的请求,必须在一个地方保存客户端信息。
# 模拟登陆
import requests
url = ''
# 反爬
·session
session :通过在服务端记录的信息确定用户身份 这里这个session就是一个指的是会话
· 处理不信任的SSL证书
SSL证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本。因为配置在服务器上,也称为SSL服务器证书。SSL 证书就是遵守 SSL协议,由受信任的数字证书颁发机构CA,在验证服务器身份后颁发,具有服务器身份验证和数据传输加密功能
http://inv-veri.chinatax.gov.cn
import requests
url = 'http://inv-veri.chinatax.gov.cn'
# get加入verify=False
res = requests.get(url, verify=False)
print(res.text)