1 urllib.request模块
1.1 版本
python2 :urllib2、urllib python3 :把urllib和urllib2合并,urllib.request
1.2 常?的?法
urllib.request.urlopen(地址) 作? :向车站发起请求并获得响应
import urllib.request # response是响应对象 response = urllib.request.urlopen('https://www.duitang.com/') # read()读取相应对象中的内容 print(response.read()) 结果输出了一系列字节流
- encode() 字符串–> 转换为bytes数据类型
- decode() bytes数据类型–> 转换为字符串 字节流 = response.read() 字符串 = response.read().decode(“utf-8”)
import urllib.request # response是响应对象 response = urllib.request.urlopen('https://www.duitang.com/') # read()读取相应对象中的内容 html = response.read().decode('utf-8') print(type(html),html) 结果转化为网页源代码格式 字符串类型 urllib.request.Request"?址",headers=“字典”) 可支持重构User-Agent;urlopen()不持重构User-Agent
- 对于有反爬的网页
import urllib.request url = 'https://www.baidu.com/' headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400' } # 1.创建请求对象 req = urllib.request.Request(url,headers=headers) # 2.获取响应对象 response = urllib.request.urlopen(req) # 3.读取响应对象的内容 read().decode('utf-8') html = response.read().decode('utf-8') print(html) 可以呈现结果
- 使用流程
- 利用Request()方法构建请求对象
- 利用urlopen()获取响应对象的方法
- 在响应对象中使用read().decode(‘utf-8’) 读取响应对象的内容
1.3 对象h> read() 读取服务器响应的内容 getcode() 返回HTTP的响应码
import urllib.request
url = 'https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
# 1.创建请求对象
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象
response = urllib.request.urlopen(req)
# 3.读取响应对象内容 read().decode('utf-8')
html = response.read().decode('utf-8')
# print(html)
print(response.getcode()) #返回状态码结果 200
print(response.geturl()) #返回实际数据的URL地址 https://www.baidu.com/
geturl() 返回实际数据的URL(防⽌重定向问题)
import urllib.request
url = 'https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
# 1.创建请求对象
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象
response = urllib.request.urlopen(req)
# 3.读取响应对象内容 read().decode('utf-8')
html = response.read().decode('utf-8')
print(response.geturl()) #返回实际数据的URL地址 https://www.baidu.com/
import urllib.request
url = 'https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
# 1.创建请求对象
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象
response = urllib.request.urlopen(req)
# 3.读取响应对象内容 read().decode('utf-8')
html = response.read().decode('utf-8')
# print(html)
print(response.getcode()) #返回状态码结果 200
print(response.geturl()) #返回实际数据的URL地址 https://www.baidu.com/
import urllib.request
url = 'https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
# 1.创建请求对象
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象
response = urllib.request.urlopen(req)
# 3.读取响应对象内容 read().decode('utf-8')
html = response.read().decode('utf-8')
print(response.geturl()) #返回实际数据的URL地址 https://www.baidu.com/
2 urllib.parse模块
2.1 常⽤⽅法
urlencode(字典),可以实现手动的将汉字变为十六进制
# https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
import urllib.parse
name = {
'wd':'海贼王'}
name = urllib.parse.urlencode(name)
print(name)
结果
wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
- 练习一
# 请输入要搜索的内容,并把搜索结果,保存到当前目录 帅哥.html
import urllib.request
import urllib.parse
# https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
# 拼接url
baseurl = 'https://www.baidu.com/s?'
name = input('请输入要搜索的内容:')
# 进行urlencode()编码
wd = {
'wd':name}
name = urllib.parse.urlencode(wd)
url = baseurl + name
# print(url)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400','Cookie':'BAIDUID=0E1D7663D747715D94313EFB4E2C33AC:FG=1; BIDUPSID=0E1D7663D747715D94313EFB4E2C33AC; PSTM=1587718856; BD_UPN=1a314753; BDUSS=lna0k2Tm1aVmV1dGgzQmlqSGRORE1EbEJrVTZXNFJNTXJlVHB5eXRmQjJRRDFmSUFBQUFBJCQAAAAAAAAAAAEAAAB73m8ltPS09LXEuMK4wjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHazFV92sxVfVT; MCITY=-%3A; BDUSS_BFESS=lna0k2Tm1aVmV1dGgzQmlqSGRORE1EbEJrVTZXNFJNTXJlVHB5eXRmQjJRRDFmSUFBQUFBJCQAAAAAAAAAAAEAAAB73m8ltPS09LXEuMK4wjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHazFV92sxVfVT; BDRCVFR[sK1aAlma4-c]=mk3SLVN4HKm; delPer=0; BD_CK_SAM=1; PSINO=1; BDRCVFR[S_ukKV6dOkf]=mk3SLVN4HKm; BD_HOME=1; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; H_PS_645EC=1ca8wohXaH4gHIjrqDXVa0cDekSx3Kaem5kzoR%2BMTsGHRIld8yQe%2BpZqvbk; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_PSSID=1421_32439_32532_32328_32348_32045_32270_32115_31322_22157'
}
# 创建请求对象
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)
结果
输出一个html文件
quote(字符串) (这个⾥⾯的参数是个字符串)
- 百度贴吧练习一
# 需求:输入要爬取贴吧的名称,输入爬取的起始页和终止页,把每一页保存到本地
# 分析:1.找url的规律
# 第一页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=0
# 第二页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=50
# 第三页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=100
# 第四页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=(n-1)*50
# 页数规律 pn = (当前页数-1)*50
# 分析:2.获取网页内容
# 分析:3.获取数据
- 使用User-Agent时候,为了不让百度知道是人是鬼在操作,引入random
import random
import urllib.request
import urllib.parse
# 随机获取一个ua,去百度上找常见的User-Agent大全.可以多放几个
headers_list = [{
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
},{
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}]
headers = random.choice(headers_list)
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 = 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(f'正在爬取第{i}页')
f.write(html)
结果

- 练习二
# import random
import urllib.request
import urllib.parse
# 读取页面的逻辑封装
def readPage(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
# 发起请求
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)
# 主函数
def main():
name = input('请输入贴吧名:')
start = int(input('请输入起始页:'))
end = int(input('请输入结束页:'))
# 对贴吧name进行编码
kw = {
'kw': name}
kw = urllib.parse.urlencode(kw)
for i in range(start,end+1):
# 拼接url
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()
结果三个页面
请输入贴吧名:帅哥
请输入起始页:1
请输入结束页:3
- 练习三 类对象实现
import urllib.request
import urllib.parse
class BaiduSpider:
def __init__(self):
#把常用的不变的放到init方法里面
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
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)
def main(self):
name = input('请输入贴吧名:')
start = int(input('请输入起始页:'))
end = int(input('请输入结束页:'))
# 对贴吧name进行编码
kw = {
'kw': name}
kw = urllib.parse.urlencode(kw)
for i in range(start, end + 1):
# 拼接url
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__':
# 如果要调用类对象中的main方法,
#先需要实例化
spider = BaiduSpider()
spider.main()
3 请求⽅式
-
GET 特点 :查询参数在URL地址中显示
-
POST 在Request⽅法中添加data参数 urllib.request.Request(url,data=data,headers=headers) data :表单数据以bytes类型提交,不能是str
-
有道翻译练习
import urllib.request
import urllib.parse
import json
# 请输入你要翻译的内容
key = input('请输入要翻译的内容:')
# 把需要提交的form表单数据转换为bytes类型的数据 为什么就知道用form表单里的东西
data = {
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15980993133958',
'sign': '8d249124b310aa8e7fa82f24049ff7b7',
'lts': '1598099313395',
'bv': '94d04da9bee8870ad9ad8714b54f2bea',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
data = urllib.parse.urlencode(data)
# 把data转换为字节
data = bytes(data,'utf-8')
# 发请求获取响应 注意需要去掉_o
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
req = urllib.request.Request(url,data=data,headers=headers)
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')
# 这是一个json类型的字符串 {"type":"EN2ZH_CN","errorCode":0,"elapsedTime":1,"translateResult":[[{"src":"money","tgt":"钱"}]]}
# 将上述html的json类型的字符串变为字典dict
r_dict = json.loads(html)
r = r_dict['translateResult'] # 结果就是这个列表[[{"src":"money","tgt":"钱"}]]
result = r[0][0]['tgt'] # [{"src":"money","tgt":"钱"}] --> 字典 {"src":"money","tgt":"钱"}
print(result)
请输入要翻译的内容:luck
运气
4 requests模块
4.1 安装
pip install requests 在开发⼯具中安装
4.2 request常⽤⽅法
requests.get(⽹址)
4.3 响应对象response的⽅法
response.text 返回unicode格式的数据(str)
print(response.text) # 返回的是str类型
response.content 返回字节流数据(⼆进制)
print(response.content) # 返回的是字节流
response.content.decode(‘utf-8’) ⼿动进⾏解码
print(response.content.decode('utf-8')) # ⼿动进⾏解码
response.url 返回url response.encode() = ‘编码’ 可以解决乱码问题
import requests
response = requests.get('http://www.qqbiaoqing.com/gaoxiao/')
# print(response.content.decode('utf-8'))
response.encoding = 'utf-8' # 如果没有这句,就会乱码
print(response.text)
4.4 requests模块发送 POST请求
import requests
import json
key = input('请输入翻译的内容')
# 把需要提交的form表单数据转换为bytes类型的数据 为什么就知道用form表单里的东西,因为输入的要素只出现在form表单里,所以去这找结果
data = {
'i': key,
'from': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '15980993133958',
'sign': '8d249124b310aa8e7fa82f24049ff7b7',
'lts': '1598099313395',
'bv': '94d04da9bee8870ad9ad8714b54f2bea',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}
res = requests.post(url,data=data,headers=headers)
res.encoding = 'utf-8'
html = res.text
r_dict = json.loads(html)
result = r_dict['translateResult'][0][0]['tgt']
print(result)
请输入翻译的内容蜘蛛侠
spider-man
4.5 requests设置代理
使⽤requests添加代理只需要在请求⽅法中(get/post)传递proxies参数就可 以了 设置代理 http://www.httpbin.org/ip 代理⽹站 ⻄刺免费代理IP:http://www.xicidaili.com/ 快代理:http://www.kuaidaili.com/ 代理云:http://www.dailiyun.com/
import requests
# 设置代理
proxy = {
'http':'116.196.85.190:3128'
}
url = 'http://www.httpbin.org/ip'
res = requests.get(url,proxies=proxy)
print(res.text)
4.6 cookie
cookie :通过在客户端记录的信息确定⽤户身份,一旦确定之后,不用重复登录
HTTP是⼀种⽆连接协议,客户端和服务器交互仅仅限于 请求/响应过程,结束后断开,下⼀次请求时,服务器会认为是⼀个新的客户端,为了维护他们之间的连接,让服务器知道这是前⼀个⽤户发起的请求,必须在⼀个地⽅保存客户端信息。
- 练习模拟登陆知乎
import requests
# resp = requests.get('https://www.baidu.com/')
#
# # print(resp.cookies.get_dict())
# 模拟登陆知乎
url = 'https://www2.zhihu.com/hot'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400','cookie':'d_c0="AIBf6s8OKxGPTsCiOuJyoRVgNBjHstjKmcg=|1587727340"; _zap=6fc01f58-8fb3-4545-a781-417edf50e819; z_c0="2|1:0|10:1590034345|4:z_c0|92:Mi4xWG5HTEV3QUFBQUFBZ0ZfcXp3NHJFU1lBQUFCZ0FsVk5xVTJ6WHdBbm5kUGtSLXJQb2FMU1hENzN4S2FmbDVaTEln|b476020625a8a9eb38d3924904d14ed3f57ad5a55b29d104cf80d35e81bea1ee"; q_c1=c02ae3a1e68047a9965dc958423c0d2a|1597549527000|1590629112000; _xsrf=gBkpgEOmNKWElWsbjf040VnefHxTTo7h; SESSIONID=oEXxVPA7EVUX5OiYt43xIOXiy7UCkPTslsTf8EGneVW; JOID=U1sQBUPv6PqCRVtPRujzLV46uYVTzs3ar296ambFyd-iaHFuY874tNpOX0pL48DS0lAf9RdCtJESk6_0u8T_Xwg=; osd=UFoUBkPs6f6BRVhOQuvzLl8-uoVQz8nZr2x7bmXFyt6ma3FtYsr7tNlPW0lL4MHW0VAc9BNBtJITl6z0uMX7XAg=; tst=h; KLBRSID=ca494ee5d16b14b649673c122ff27291|1598232043|1598231842; tshl='
}
resp = requests.get(url,headers=headers)
print(resp.text)
4.7 session
session :通过在服务端记录的信息确定⽤户身份 这⾥这个session就是⼀个指的是会话
- 案例演示 首先对12306验证图片的获取–显得臃肿
import base64
# 需要删掉 data:image/jpg;base64,
url = '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