您的位置:首页 > 编程语言 > Python开发

Python3.5爬虫urllib系列之三

2017-07-18 12:02 483 查看

1,简述

所谓网页抓取,就是把URL地址中指定的网络资源从网络流中抓取出来。在Python中有很多库可以用来抓取网页。

在python2中自带urllib和urllib2。二者区别如下:

1,urllib 模块仅可以接受URL,不能创建 设置headers 的Request 类实例;

2,但是 urllib 提供 urlencode 方法用来产生GET查询字符串,而 urllib2 则没有。(这是 urllib 和 urllib2 经常一起使用的主要原因)

3,编码工作使用urllib的urlencode()函数,帮我们将key:value这样的键值对,转换成”key=value”这样的字符串,解码工作可以使用urllib的unquote()函数。( 注意,不是urllib2.urlencode())

在python3中urllib2被改为urllib库下request模块。编码使用urllib库下parse模块

from urllib import parse
# url转码操作,只有转码后浏览器才会识别该url
kw = {'name': '中国'}
res = parse.urlencode(kw)
print(res)
res2 = parse.unquote(res)
print(res2)
# 结果如下:
# name=E5%B0%8F%E5%8F%AF
# name=中国


注意:本文采用python3.5的python爬虫环境。

2,urlopen发送请求,返回响应案例

# 导入urllib 库下request模块
from urllib import request

# 向指定的url发送请求,并返回服务器响应的类文件对象
response = request.urlopen("http://www.baidu.com")

# 类文件对象支持 文件对象的操作方法,如read()方法读取文件全部内容,返回字符串
html = response.read()

# 打印字符串
print(html)


3,Request构造请求对象

# 导入urllib 库下request模块
from urllib import request

# url 作为Request()方法的参数,构造并返回一个Request对象
req = request.Request("http://www.baidu.com")

# Request对象作为urlopen()方法的参数,发送给服务器并接收响应
response = request.urlopen(req)

html = response.read()

print(html)


注意:

新建Request实例,除了必须要有 url 参数之外,还可以设置另外两个参数:

1,data(默认空):提交的Form表单数据,同时 HTTP 请求方法将从默认的 “GET”方式 改为 “POST”方式。

2,headers(默认空):参数为字典类型,包含了需要发送的HTTP报头的键值对。

4,User-Agent伪装成浏览器

浏览器 就是互联网世界上公认被允许的身份,如果我们希望我们的爬虫程序更像一个真实用户,那我们第一步就是需要伪装成一个被浏览器。用不同的浏览器在发送请求的时候,会有不同的 User-Agent 报头。

python2中的urllib2默认的User-Agent头为:Python-urllib/x.y (x和y 是Python 主.次 版本号,例如 Python-urllib/2.7)

from urllib import request

def loadPage():
# 包含一个请求报头的headers, 发送的请求会附带浏览器身份发送
headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)"}
# 构造一个请求对象
req = request.Request("http://www.baidu.com/", headers=headers)
# 发送http请求,返回服务器的响应内容
# response响应是一个类文件对象
response = request.urlopen(req)
# 类文件对象支持文件操作的相关方法,比如read():读取文件所有内容,返回字符串
return response.read()

if __name__ == "__main__":
# print __name__
html = loadPage()
# 打印字符串,也就是整个网页的源码
print(html)


5,添加更多的Header信息

在 HTTP Request 中加入特定的 Header,来构造一个完整的HTTP请求消息。

可以通过调用Request.add_header() 添加/修改一个特定的header 也可以通过调用Request.get_header()来查看已有的header。

# 导入urllib 库下request模块
from urllib import request

url = "http://www.baidu.com"

# IE 9.0 的 User-Agent
user_agent = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"}
req = request.Request(url, headers=user_agent)

# 也可以通过调用Reques.add_header() 添加/修改一个特定的header为长链接
req.add_header("Connection", "keep-alive")

# 也可以通过调用Request.get_header()来查看header信息
# req.get_header(header_name="Connection")

response = request.urlopen(req)

print(response.code)  # 可以查看响应状态码
# 网页源代码
html = response.read()

print(html)


6,随机添加/修改User-Agent

from  urllib import request
import random

def loadPage(url):
# User-Agent 列表
useragent_list = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3"
]
# 随机选择一个User-Agent字符串
# random.choice()这个方法可以从列表中随机的取出一个元素
user_agent = random.choice(useragent_list)

# 构造请求对象
req = request.Request(url)
# 添加一个请求报头,添加的时候是User-Agent
req.add_header("User-Agent", user_agent)
# 查看指定请求报头,获取的时候一定是User-agent
print(req.get_header("User-agent"))

# 发送请求,返回服务器响应
reseponse = request.urlopen(req)
# 返回响应的html内容
return reseponse.read()

if __name__ == "__main__":
url = input("请输入需要抓取的网页:")
html = loadPage(url)
print(html)


7,GET方式请求,爬取贴吧案例

# 处理HTTP请求,在python2中是urllib2,在python3中是urllib.request
from urllib import request, parse

def loadPage(url, filename):
'''
作用:根据url发送请求,获取服务器响应文件
url:需要爬取的url地址
filename: 文件名
'''
print("[LOG]: 正在下载" + filename)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6"}
# 构造请求对象
req = request.Request(url, headers=headers)
# 发送请求,返回响应结果
response = request.urlopen(req)
if response.getcode() == 200:
return response.read()
else:
print("[ERR]: 下载失败...")

def writePage(html, filename):
"""
作用:保存服务器响应文件到本地磁盘文件里
html: 服务器响应文件
filename: 本地磁盘文件名
"""
print("[LOG]: 正在写入" + filename)
with open(filename, "wb") as f:
f.write(html)

def tiebaSpider(url, beginPage, endPage):
"""
作用:负责处理url,分配每个url去发送请求
url:需要处理的第一个url
beginPage: 爬虫执行的起始页面
endPage: 爬虫执行的截止页面
"""
for page in range(beginPage, endPage + 1):
pn = (page - 1) * 50
# 对pn进行转码后,才能在浏览器中识别
keyword = parse.urlencode({"pn": pn})
fullurl = url + "&" + keyword
print(fullurl)
# 爬取到的数据存放的文件名称
filename = "第" + str(page) + "页.html"
html = loadPage(fullurl, filename)
writePage(html, filename)

if __name__ == "__main__":
tiebaName = input("请输入需要爬取的贴吧名:")
beginPage = int(input("请输入爬取的起始页:"))
endPage = int(input("请输入爬取的终止页: "))

# "https://tieba.baidu.com/f? kw=%E6%9D%8E%E6%AF%85&pn=50"
baseURL = "http://tieba.baidu.com/f?"
keyword = {"kw": tiebaName}
kw = parse.urlencode(keyword)
url = baseURL + kw
tiebaSpider(url, beginPage, endPage)


8,POST方式爬取有道词典案例

from urllib import request, parse

def loadPage():
# 新版本的有道翻译的接口
# url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule&sessionFrom=null"
# 老版本的有道翻译的接口
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&sessionFrom=null"

# i = bytes(input("请输入需要翻译的句子:").encode('utf-8'))
i = input("请输入需要翻译的句子:")
# form表单数据,通过网页源代码可查看携带的请求参数
formdata = {
"i": i,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
# "salt" : "1500253430162",
# "sign" : "db86dafb01c61b4c5bc85bc0868ff7f6",
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_CL1CKBUTTON",
"typoResult": "true",
}

# 将数据转为url编码,注意这个地方要加encode()编码方式,否则会报错如下:
# "POST data should be bytes or an iterable of bytes. It cannot be of type str.
data = parse.urlencode(formdata).encode(encoding='utf8')

# 请求报头
headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)"}

# 构造一个请求,因为有data参数,所有请求会从默认的get变成post
# 发送post请求同时,会把data数据传输到指定的url地址
req = request.Request(url, data=data, headers=headers)

# 发送请求,返回响应
response = request.urlopen(req)
# 去除字符串首尾的空格
content = response.read().strip()

# print content
# 将字符串格式的字典,转换为真正的字典
content = eval(content)

print(content)

# 取出字典的值
print(content["translateResult"][0][0]["tgt"])

if __name__ == "__main__":
loadPage()

# 结果如下:
# 请输入需要翻译的句子:hello

# 返回的json字符串如下:
# {'type': 'EN2ZH_CN',
#  'translateResult': [[{'src': 'hello', 'tgt': '你好'}]],
#  'smartResult': {'type': 1, 'entries': ['', 'n. 表示问候, 惊奇或唤起注意时的用语', 'int. 喂;哈罗', 'n. (Hello)人名;(法)埃洛']},
#  'errorCode': 0,
#  'elapsedTime': 1 }

# 最终结果:
# 你好


9,处理HTTPS请求 SSL证书验证

现在随处可见 https 开头的网站,urllib2可以为 HTTPS 请求验证SSL证书,就像web浏览器一样,如果网站的SSL证书是经过CA认证的,则能够正常访问,如:https://www.baidu.com/等…

如果SSL证书验证不通过,或者操作系统不信任服务器的安全证书,比如浏览器在访问12306网站如:https://www.12306.cn/mormhweb/的时候,会警告用户证书不受信任。(据说 12306 网站证书是自己做的,没有通过CA认证)

如果没有ssl证书认证,会报如下错误:

urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:645)>


from urllib import request
import ssl

# 表示忽略网站的不合法证书认证
context = ssl._create_unverified_context()

headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)"}

req = request.Request("https://www.12306.cn/mormhweb/", headers=headers)

# 在urlopen()添加context参数,请求将忽略网站的证书认证
response = request.urlopen(req, context=context)

print(response.read())


关于CA数据证书认证

CA(Certificate Authority)是数字证书认证中心的简称,是指发放、管理、废除数字证书的受信任的第三方机构,如北京数字认证股份有限公司、上海市数字证书认证中心有限公司等…

CA的作用是检查证书持有者身份的合法性,并签发证书,以防证书被伪造或篡改,以及对证书和密钥进行管理。

现实生活中可以用身份证来证明身份, 那么在网络世界里,数字证书就是身份证。和现实生活不同的是,并不是每个上网的用户都有数字证书的,往往只有当一个人需要证明自己的身份的时候才需要用到数字证书。

普通用户一般是不需要,因为网站并不关心是谁访问了网站,现在的网站只关心流量。但是反过来,网站就需要证明自己的身份了。

比如说现在钓鱼网站很多的,比如你想访问的是www.baidu.com,但其实你访问的是www.daibu.com”,所以在提交自己的隐私信息之前需要验证一下网站的身份,要求网站出示数字证书。

一般正常的网站都会主动出示自己的数字证书,来确保客户端和网站服务器之间的通信数据是加密安全的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python 爬虫