python2环境下关于urllib2的使用可以学习这篇文章。本文主要针对python3环境下使用urllib模块实现简单程序爬虫。
链接:https://www.jianshu.com/p/31833117b34b
urllib模块的使用
1.数据编码处理
- 我们通过爬虫程序可以得到网站返回的数据,但是返回的数据在展示过程中,出现了乱码的问题,是因为网站本身有自己的字符编码(通常情况下是 UTF-8),我们程序在采集完成之后在控制台进行展示的过程中是使用本地默认编码(windows 一般是 gbk、unix 中一般是 utf-8),如果两部分编码不一致,就会出现乱码的问题。
- 网页结构中的编码,一般会定义在标签中,所以爬虫采集网页数据时可以分成两个步骤进行操作,先采集批量网页中的一个网页查看编码格式,然后在代码中根据指定的编码格式进行解码,得到正确数据之后,再进行批量网页数据的采集;这样的操作方式是手工指定编码方式。
# 引入依赖模块
from urllib import request
# 向服务器发送请求,获取响应对象
response = request.urlopen("https://www.baidu.com")
# 获取包含在响应中的数据
html = response.read()
# 解码
html = html.decode('utf-8')
# 打印结果
print(html)
结果为:
<html>
<head>
<script>
location.replace(location.href.replace("https://","http://"));
</script>
</head>
<body>
<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>
Process finished with exit code 0
- 但是手工指定编码方式的操作,存在很大的局限性,批量网页处理过程中一旦出现不同编码格式的网页,很容易造成程序异常导致数据遗漏,所以我们可以通过 python 第三方模块进行目标数据的分析判断,得到一个具体的编码格式,然后通过该检测的编码格式进行数据的解码工作
- remark:通过chardet 模块可以直接检测目标数据的编码格式,但是编码格式只是一个检测的概率值,所以在编码解码错误的情况下,需要人工介入进行解码操作。
# 引入依赖模块
from urllib import request
import chardet
# 向服务器发送请求,获取响应对象
response = request.urlopen("https://www.80s.tw/")
# 获取包含在响应中的数据
html = response.read()
# 验证编码
encoding = chardet.detect(html).get('encoding')
# 解码:
html = html.decode(encoding)
# 打印结果
print(html)
2.请求对象包装
- 前面的代码中,目标网站的 url 地址就是一个普通的字符串,通过该字符串可以发起一个具体的请求,但是在网站操作过程中,客户端发送的一个请求可能会包含较多的格式数据如请求 url、请求头、请求体、参数、 cookie 等等数据;
- 爬虫操作就是在模拟真实用户的操作,请求的操作也可以通过请求对象的方式进行模拟,在python3 中的 urllib 模块下的 Request 类型,就是一个模拟发送的请求对象。
- 具体的操作代码如下:
# 引入依赖的模块
from urllib import request
import chardet
# 将请求包装成请求对象
req = request.Request('https://www.80s.tw/')
# 通过 urlopen 发送请求对象给服务器,得到服务器响应数据
response = request.urlopen(req)
# 得到响应数据
html = response.read()
# 编码检测并解码
html = html.decode(chardet.detect(html).get('encoding'))
print(html)
3.请求头设置
- 一个完整的请求,对于请求信息的描述,主要包含在请求头(request header)中,请求头中对于请求的数据格式、请求的数据类型、请求的语言环境、请求是否保持和服务器的连接、请求的 cookie、客户端身份信息等都进行了描述性的定义,可以通过网络抓包工具可以明确的查看到请求中包含的各项具体信息。
- web 发展之初的请求也不是这么复杂,主要是在不同浏览器软件兴起之后,由于浏览器软件之间的差异,导致浏览器从服务器获取的数据展示风格出现了迥异的误差,所以对于客户端的浏览器信息需要传递给服务器进行区别处理,于是正常的请求中包含了大量的用于描述客户端信息的组成部分,该部分就是请求头;请求头是一个 like dict 的对象,一个正常的请求头包含的内容一般如下:
--- Accept 接受响应数据的格式
--- Accept-Encoding 接受响应数据的编码
--- Accept-languate 接受响应数据的语言环境
--- Connection 是否保持连接
--- Cookie 会话跟踪数据
--- Upgrade-insecure-Requests 是否安全请求
--- Referer 反外链限制
--- User-agent 浏览器代理
--- more..
- 在 web 发展的一段时间中,由于基于 TCP 协议建立连接的 BUG,出现了大量的针对网站的DDOS 攻击手段,通过代码程序频繁给服务器发送不建立连接的请求导致服务器大量负载被空置占用,导致的结果就是有效用户不能正常请求服务器的数据,就是传说中的拒绝服务攻击手段,所以现在主流网站一般都会针对客户端发送的请求进行甄别,最主要的一个信息就是 User-agent 浏览器代理,该代理数据中描述的就是发送请求的客户端使用的系统 OS的信息、浏览器软件信息及版本信息。
- 对于服务器设置的通过验证 User-agent 来标识是否正常请求的方式,在爬虫程序中可以通过设置请求头来完成模拟真实请求的方式.
from urllib import request
import chardet
import random
# 定义多个 user-agent
my_headers = [
{'User-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60'},
{'User-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2
(KHTML, like Gecko) Version/5.1.7 Safari/534.57.2'},
{'User-agent': 'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10)
Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10'},
{'User-agent': 'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1)
Gecko/20061208 Firefox/2.0.0 Opera 9.50'},
]
# 包装请求# 爬虫请求头手工添加:添加方式 1
req = request.Request('https://www.80s.tw/',
headers=random.choice(my_headers))
# 请求数据
response = request.urlopen(req)
# 获取并验证编码
html = response.read()
encoding = chardet.detect(html).get('encoding')
html = html.decode(encoding)
# 打印结果
print(html)