urllib2的使用
所谓网页抓取,就是把URL地址中指定的网络资源从网络中读取出来,保存到本地或者数据库。在Python中有很多库可以抓取网页,我们先学习urllib2,
1、urllib2是python2.7自带的模块(不需要下载,导入就可以使用)
2、urllib2官网:https://docs.python.org/2/library/urllib2.html
3、urllib2源码:https://hg.python.org/cpython/file/2.7/Lib/urllib2.py
4、urllib2在python3.x中改为urllib.request
目录清单
1、入门小程序(了解爬虫获取数据的步骤和意思)
2、request对象的操作
3、请求头设置——User-Agent代理
4、请求方式(GET和POST)
5、handler处理器和自定义opener
6、会话跟踪(cookie)
7、异常错误处理
1、入门
首先通过一个小程序来认识爬虫
demo01
# -*- coding:utf-8 -*-
#中文注释头
#导入urllib2库
import urllib2
#向指定的url发送请求,并返回服务器响应的类文件对象
response = urllib2.urlopen("http://www.baidu.com")
#类文件对象支持文件对象的操作方法,如read()方法读取文件全部内容,返回字符串
content = response.read()
#打印内容
print content
通过运行,在控制台可以得到百度网页的源码数据
<!doctype html>
<html>
<head>
<title>百度一下,你就知道</title>
...
...
</html>
实际上,如果我们在浏览器上打开百度首页,右键选择“查看网页源代码”,你会发现,和我们刚刚打印出来的是一模一样。也就是说,上面的4行代码就已经帮我们把百度首页的全部代码爬了下来。
至此,我们就可以说爬虫程序是根据一定的规则采集获取网络上的数据
一个基本的url请求对应的python代码真的非常简单。
2、Request
上述程序我们可以了解爬虫程序的步骤,而底层操作过程是将请求和响应分步进行的
demo02
# -*- coding:utf-8 -*-
#添加注释,指定当前源代码支持中文操作
#导入urllib2库
import urllib2
#url作为request()方法的参数,构造并返回一个request对象
request = urllib2.Request("http://www.baidu.com")
#request对象作为urlopen()方法的参数,发送给服务器并接受响应
response = urllib2.urlopen(request)
content = response.read()
print content
运行结果是完全一样的,
新建的Request,除了url参数外,还可以设置另外两个参数:
1、data(默认为空),是伴随url提交的数据(比如要POST的数据),同时HTTP请求将从"GET"变成"POST"方式
2、headers(默认为空):是一个字典,包含了需要发送HTTP报头的键值对
3、User-Agent
上述代码,爬虫程序已经开发成功并采集数据,如果我们通过抓包工具进行请求查看时,你会发现一个很严重的问题,赤裸裸显示我们的身份是python urllib2的字样,这不是以迅雷不及掩耳之势用爬虫的身份直接访问服务器么,这样略有唐突。就好比你家门没有锁,老王以一个路人的身份直接闯进去,显然是没有礼貌的。而且有些网站不喜欢被程序访问(非人为操作),很容易被服务器进行分析过滤并屏蔽访问。
但是我们以一名合法的身份去请求网站,显然我们就是受欢迎的。所以,我们要对发起请求的爬虫程序进行伪造,就是给我们的代码加上一个身份。可以通过设置请求中的User-Agent来实现
demo03
# -*- coding:utf-8 -*-
import urllib2
url = "http://www.taobao.com"
# IE9.0的User-Agent,包装在header中
headers = {
"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"
}
#url和header一起构建request请求,这个请求将附带IE9.0浏览器的User-Agent
request = urllib2.Request(url=url, headers=headers)
response = urllib2.urlopen(request)
content = response.read()
print content
现在就是将爬虫程序发送的请求伪造成浏览器发送的请求,从而让我们拥有一个合法的身份去访问网站
4、请求方式GET和POST
下面我们同两个案列来学习GET和POST
GET方式:
GET请求一般用于我们向服务器获取数据,比如说,我们在百度搜索“黄鹂鸟”:https://www.baidu.com/s?wd=黄鹂鸟
demo04
# -*- coding:utf-8 -*-
# 导入需要的包
from urllib2 import Request, urlopen
from urllib import urlencode
# 定义url地址和访问的数据
url = "http://www.baidu.com/s?"
data = {
"wd": "黄鹂鸟",
}
#处理完整的请求
fulurl = url + urlencode(data)
request = Request(fulurl)
response = urlopen(request)
print response.read()
POST方式
在Request请求对象里,我们传送data参数,data是一个字典,里面要匹配键值对。通过有道翻译做案例:
demo05
# -*- coding:utf-8 -*-
# 引入需要的模块
from urllib2 import Request, urlopen
from urllib import urlencode
import time
import random
import hashlib
# 真实翻译地址
url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
# 处理加密字段
n = raw_input("请输入要翻译的词汇:")
c = "fanyideskweb"
x = "aNPG!!u6sesA>hBAW1@(-"
r = str(int(time.time() * 1000) + random.randint(1, 10))
# 加密字段
sign = hashlib.md5(c + n + r + x).hexdigest()
# 请求头设置
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Origin": "http://fanyi.youdao.com",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Referer": "http://fanyi.youdao.com/",
"Cookie": "OUTFOX_SEARCH_USER_ID_NCOO=1092450716.3850443; OUTFOX_SEARCH_USER_ID=-1512266810@10.168.1.241; JSESSIONID=aaal2mcR1N1zx5rcovkdw; fanyi-ad-id=39535; fanyi-ad-closed=1; ___rl__test__cookies=1515335942852"
}
# 请求的表单数据
form_data = {
"i": n,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": c,
"salt": r,
"sign": sign,
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTIME",
"typoResult": "false",
}
data = urlencode(form_data)
# 构建请求对象
request = Request(url, data=data, headers=headers)
response = urlopen(request)
print(response.read())
5、自定义的opener对象
- opener是 urllib2.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构建好的)。
- 但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能:
1、使用相关的 Handler处理器 来创建特定功能的处理器对象;
2、然后通过 urllib2.build_opener()方法使用这些处理器对象,创建自定义opener对象;
3、使用自定义的opener对象,调用open()方法发送请求。- 如果程序里所有的请求都使用自定义的opener,可以使用urllib2.install_opener() 将自定义的 opener 对象 定义为 全局opener,表示如果之后凡是调用urlopen,都将使用这个opener(根据自己的需求来选择)
一个简单的自定义opener()
demo06
# -*- coding:utf-8 -*-
import urllib2
# 构建一个HTTPHandler 处理器对象,支持处理HTTP请求
http_handler = urllib2.HTTPHandler()
# 调用urllib2.build_opener()方法,创建支持处理HTTP请求的opener对象
opener = urllib2.build_opener(http_handler)
# 构建 Request请求
request = urllib2.Request("http://www.baidu.com/")
# 调用自定义opener对象的open()方法,发送request请求
response = opener.open(request)
print response.read()
ProxyHandler处理器(代理设置)
使用代理IP,这是爬虫/反爬虫的大招,通常也是最好用的。
在反爬的操作过程中,有一种反爬虫操作是针对出现异常访问量的ip地址进行封锁的操作,如果使用自己的真实ip地址访问,很有可能导致自己的ip地址被封,就会禁止访问这个网站。
所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算一个ip地址被封,我们还有千千万万个ip可以使用。
demo07
# -*- coding:utf-8 -*-
import urllib2
# 创建代理处理器
proxy_handler = urllib2.ProxyHandler({'http': '61.135.217.7:80'})
# 创建Opener对象
proxy_opener = urllib2.build_opener(proxy_handler)
# 打开指定的网址
response = proxy_opener.open("https://www.taobao.com")
print response.read()
免费的开放代理获取基本没有成本,我们可以在一些网站上收集这些免费代理,测试后如果可以用,就把它们收集起来用在爬虫上面。免费短期代理网站举例:
- 西刺免费代理IP
- 快代理免费代理
- Proxy360代理
-
全网代理IP
如果代理IP足够多,就可以像随机获取User-Agent一样,随机选择一个代理去访问网站,提高了获取数据的效率。
6、会话跟踪
在很多网站上,都使用了基于cookie的会话跟踪技术。什么是cookie?cookie是指某些网站服务为了辨别用户身份和进行Session跟踪,而储存在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话。
在进行爬虫的操作当中,我们会经常使用cookie的操作。对于cookie,最原始的方法就是在请求头中设置cookie的字段,通过抓包工具给cookie设置了固定不变的字段,在实际中,cookie是频繁不断的在变化。
python提供了cookielib库,该模块主要的对象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。
可以很方便的实现cookie的数据操作。其实大多数情况下,我们只用CookieJar(),如果需要和本地文件交互,就用 MozillaCookjar() 或 LWPCookieJar()
demo08
- 首先获取访问网站的cookie值
# -*- coding:utf-8 -*-
import urllib2
import cookielib
# 创建一个基于cookie核心操作对象
cookie = cookielib.CookieJar()
#一个基于cookie的对象
handler = urllib2.HTTPCookieProcessor(cookie)
# 可以操作cookie的opener对象
opener = urllib2.build_opener(handler)
# 打开目标网站
response = opener.open("http://fanyi.youdao.com")
# 查看cookie数据
for i in cookie:
print i.name + "--" + i.value
- 将访问到的cookie保存到本地
# -*- coding:utf-8 -*-
import urllib2
import cookielib
cookie = cookielib.MozillaCookieJar("youdao.txt")
handler = urllib2.HTTPCookieProcessor(cookie)
opener = urllib2.build_opener(handler)
response = opener.open("http://fanyi.youdao.com")
# 保存cookie到文件
cookie.save()
- 从本地加载cookie数据
# -*- coding:utf-8 -*-
import urllib2
import cookielib
cookie = cookielib.MozillaCookieJar()
# 加载cookie中的数据
cookie.load("youdao.txt")
handler = urllib2.HTTPCookieProcessor(cookie)
opener = urllib2.build_opener(handler)
response = opener.open("http://fanyi.youdao.com")
# 完整代码参考post请求
7、异常处理
urllib2的异常错误处理。这里我们主要说URLError和HTTPError,以及对他们的错误处理
URLError
URLError产生的主要原因:
1、没有网络连接
2、服务器连接失败
3、找不到指定的服务器
我们可以使用 try except语句来捕获响应的异常,下面我们访问一个不存在的域名:
demo09
# -*- coding:utf-8 -*-
import urllib2
request = urllib2.Request("http://www.lovehuangliniao.com")
try:
urllib2.urlopen(request, timeout=3)
except urllib2.URLError, err:
print err
运行结果就是没有找到指定的服务器
<urlopen error [Errno 8] nodename nor servname provided, or not known>
HTTPError
HTTPError是URLError错误的子类,发送一个请求时,在服务器上就会产生一个相对应的response相应对象,里面包含一个数字“响应状态码”。
响应状态码
如果urlopen或opener.open不能处理的,会产生一个HTTPError,对应相应的状态码,HTTP状态码表示HTTP协议所返回的响应的状态。
demo10
# -*- coding:utf-8 -*-
import urllib2
request = urllib2.Request("http://www.dailiyun.com/huang")
try:
response = urllib2.urlopen(request)
except urllib2.HTTPError, err:
print err.code
print err
运行结果:
404
HTTP Error 404: Not Found
HTTP Error,错误代号是404,错误原因是Not Found,说明服务器无法找到被请求的页面。
通常产生这种错误的,要么url不对,要么ip被封。