Python 爬虫(2)--- 请求模块urllib和request

爬虫请求模块

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)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值