python爬虫之urllib库(二)
python爬虫之urllib库(二)
urllib库
超时设置
网页长时间无法响应的,系统会判断网页超时,无法打开网页。对于爬虫而言,我们作为网页的访问者,不能一直等着服务器给我们返回错误信息,耗费时间太久。因此,我们在爬取网页的时候可以设置超时异常的值。
import urllib.request file=urllib.request.urlopen("http://yum.iqianyue.com",timeout=30) #timeout=30,表示30秒以后产生超时异常
data=file.read()
HTTP协议请求
HTTP请求即HTTP请求报文首行(协议方法,请求URL,协议版本)中的协议方法,HTTP请求方法主要有:
GET请求:通过URL来传递请求信息,获取服务器资源。由于GET请求可以把要传递的请求信息添加在URL上,不安全性表现在可以通过地址栏URL信息看到传递的信息。
POST请求:向服务器提交数据,如表单提交,通常使用Post请求。
PUT请求:请求服务器存储一个资源,通常需要指定存储位置。
DELETE请求:请求服务器删除一个资源。
HEAD请求:请求获取响应的报头信息,对于响应的主体内容不需要。
OPTIONS请求:获得请求URL所支持的HTTP方法
四种HTTP请求方法区别:GET--查,POST--增,PUT--改,DELETE--删。
GET请求实现
在百度首页输入关键词查询,不断更换关键词可以看到地址栏中URL的变化。分析可以得出:‘https://www.baidu.com/s?wd=’为URL主要部分,在关键词检索字段wd后添加关键词,即可实现百度搜索。
构造get请求,实现自动爬取百度查询关键词为hello的结果。
import urllib.request core_url = 'http://www.baidu.com/s?wd='
keywords = 'hello'
full_url = core_url + keywords
req = urllib.request.Request(full_url)
data = urllib.request.urlopen(req).read() with open('hello.html', 'wb') as f:
f.write(data)
上述关键词如果变成中文,会出现报错:UnicodeEncodeError: 'ascii' codec can't encode characters in position 10-11: ordinal not in range(128),原因:python爬虫之urllib库(一)提到过URL编码,URL只会承认一部分ASCII码中字符,对于汉字等特殊符号是需要编码的。对于一个参数使用字符串结合request模块给URL传参:urllib.request.quote(str);对于多个参数使用字典结合parse模块给URL传参:urllib.parse.urlencode(dict)。
一个参数
import urllib.request core_url = 'http://www.baidu.com/s?wd='
keywords = '您好'
keywords_encode = urllib.request.quote(keywords) # URL参数编码
full_url = core_url + keywords_encode
req = urllib.request.Request(full_url)
data = urllib.request.urlopen(req).read() with open('hello.html', 'wb') as f:
f.write(data)
多个参数
import urllib.request
import urllib.parse core_url = 'http://www.baidu.com/s?' # 关键词字段减掉
keywords = { # 多个参数
'wd': '您好',
'rsv_spt': 1,
'rsv_iqid': 0x8c77175600037633,
}
keywords_encode = urllib.parse.urlencode(keywords) # 多个参数url编码
full_url = core_url + keywords_encode
req = urllib.request.Request(full_url)
data = urllib.request.urlopen(req).read() with open('hello.html', 'wb') as f:
f.write(data)
POST请求实现
POST请求多用于提交表单来实现注册登录。爬虫面对需要注册登录的网页一定是需要登录访问网页以后才可以对网页内容进行爬取的,可以构造POST请求实现自动登录爬取网页。
import urllib.request
import urllib.parse url = 'http://data.stats.gov.cn/login.htm' # url必须是登录或者注册页面的url地址 国家数据统计局官网登录url
form_data = {
'username': '545859297@qq.com', # 表单数据,登录时输入的信息,对应邮箱和密码。不再是url参数了,注意区分
'keyp': 'bushizhenmima', # 注意字典中的key需要使用页面中input输入框的name属性的属性值。别试我账号密码!!!
# 浏览器打开上述网页,确实验证码输入,登录不会成功
}
form_data_deal = urllib.parse.urlencode(form_data).encode('utf-8') # POST请求data属性需要传入bytes类型,而且字典需要通过urlencode连接
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
}
req = urllib.request.Request(url, data=form_data_deal, headers=headers)
data = urllib.request.urlopen(req).read() with open('country-data.html', 'wb') as f:
f.write(data)
代理服务器设置
多次使用一个IP地址去爬取网页,服务器可以轻易察觉属于不正常访问行为,可能会对该IP地址设置拒绝访问(封IP),也可能会对用户账号处理(封账号)。使用代理服务器可以轻松换IP地址,即使用代理服务器的IP地址访问页面,而不使用我们真正的IP地址,所谓“偷梁换柱”。
代理服务器可以分为:免费代理、付费代理。免费代理可以通过网页搜索“免费代理服务器”获得,付费代理可以通过购买获得。代理基本格式:IP:port(代理IP:端口号)
免费代理添加需要先创建处理器handler,再由build_open()创建opener对象,调用opener中的open()方法爬取页面,不能再使用urlopen()发送请求爬取了。
使用handle+opener发送请求爬取页面的方法:
import urllib.request def handler_opener():
url = 'https://www.baidu.com' handler = urllib.request.HTTPHandler() # 常见HTTP处理器
opener = urllib.request.build_opener(handler) # 调用buile_open()创建opener对象 response = opener.open(url) # 调用open()方法发送HTTP请求
response_str = response.read().decode('utf-8') return response_str result = handler_opener()
with open('baidu.html', 'w', encoding='utf-8') as f:
f.write(result)
免费代理添加及使用方式:
import urllib.request def free_proxy():
url = 'http://www.baidu.com' proxy = {
'http': 'http;//116.209.57.195:9999', # 分为http和https两种协议版本,https是更加安全的http,在http基础上加入安全层SSL
# 'https': 'https://118.182.33.7:42801'
} proxy_handler = urllib.request.ProxyHandler(proxy) # 创建代理处理器,使用ProxyHandle
opener = urllib.request.build_opener(proxy_handler) response = opener.open(url)
response_str = response.read() # 注意与上例不同 return response_str result = free_proxy()
with open('baidu-free.html', 'wb') as f: # 注意与上例不同
f.write(result)
付费代理添加有两种方式:
方式一
import urllib.request def free_proxy():
url = 'https://www.baidu.com' proxy = {
'http': 'http;//222.139.245.130:58424', # 分为http和https两种协议版本,https是更加安全的http,在http基础上加入安全层SSL
# 'https': 'https://118.182.33.7:42801'
} proxy_handler = urllib.request.ProxyHandler(proxy) # 创建代理处理器
opener = urllib.request.build_opener(proxy_handler, urllib.request.HTTPHandler) # 这个可以缺省HTTPHandler,下面为源码解释
'''
The opener will use several default handlers, including support for HTTP, FTP and when applicable HTTPS.
If any of the handlers passed as arguments are subclasses of the default handlers, the default handlers will not be used.
''' response = opener.open(url)
response_str = response.read() # 注意与上例不同 return response_str result = free_proxy()
with open('baidu-free.html', 'wb') as f: # 注意与上例不同
f.write(result)
方式二
import urllib.request def fee_proxy():
url = 'http://www.baidu.com' # 付费代理IP第二种方式
user_name = 'admin'
password = ''
proxy_ip = 'http://121.61.1.222:9999'
proxy_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm() # 创建密码管理器
proxy_manager.add_password(None, proxy_ip, user_name, password) proxy_handler = urllib.request.ProxyBasicAuthHandler(proxy_manager) # 代理IP验证处理器
proxy_opener = urllib.request.build_opener(proxy_handler) response = proxy_opener.open(url)
response_str = response.read().decode('utf-8') return response_str data = fee_proxy()
with open('baidu-fee.html', 'w', encoding='utf-8') as f:
f.write(data)
代理服务器地址是具有时效性的,尤其是免费代理IP,如果代理服务器地址失效或者填写错误,会返回URLError。通常使用代理服务器进行网页爬取出现URLError,要考虑是否是代理IP失效的原因。
DebugLog
调试日志是记录程序运行状态的记录,对于自动化爬虫而言,调试日志是不可或缺的。通过设置Debuglog,可以实现程序边运行边打印调试日志的需求。
调试日志的配置方法:
- 分别使用urllib.request.HTTPHandler()和urllib.request.HTTPSHandler()设置参数debuglevel=1,开启并设置bug级别。
- 使用urllib.request.build_opener()创建自定义的opener对象,并设置1中的值作为参数。
- 使用urllib.request.install_opener()创建全局的opener对象,使得opener对象不仅可以调用open()方法,也可以使用urlopen()发送HTTP请求。
- 调用open()方法或者使用urllib.request.urlopen()发送HTTP请求。
import urllib.request url = 'http://www.baidu.com' http_handler = urllib.request.HTTPHandler(debuglevel=1)
https_handler = urllib.request.HTTPSHandler(debuglevel=1)
opener = urllib.request.build_opener(http_handler, https_handler)
urllib.request.install_opener(opener) response = urllib.request.urlopen(url) # 请求方式一
# response = opener.open(url) # 请求方式二
URLError
程序在执行或者搭建过程中,不可避免的会出现错误或者异常,错误通常是指不合语言本身规则且不可控的使用方式,异常是指合乎语言规则且可控的使用方式。网络爬虫中,网页内容和结构的迭代更新以及网络环境等因素都会产生影响,甚至异常。因此,合理处理异常对于爬虫而言是很重要的。
异常主要为URLError类以及其子类HTTP类,处理方法是使用urllib.error模块和try...except语句,产生URLError异常的原因有:
- 连接不上服务器
- 远程URL不存在
- 无网络
- 触发了HTTPError
import urllib.request
import urllib.error url = 'http://sad.blog.csdn.net' try:
rep = urllib.request.urlopen(url)
except urllib.error.URLError as e:
print(e)
else:
print(rep)
当触发HTTPError,可以直接使用HTTPError类,可以查看异常后的状态码以及原因短语。
import urllib.request
import urllib.error url = 'http://sad.blog.csdn.net' try:
rep = urllib.request.urlopen(url)
except urllib.error.HTTPError as e:
print(e.code, e.reason)
else:
print(rep)
常见的状态码以及原因短语有:
状态码 | 原因短语(英文) | 原因短语(中文) |
200 | OK | 正常 |
301 | Moved Permanently | 重新定向新的URL,永久性 |
302 | Found | 重新定向新的URL,非永久性 |
304 | Not Modified | 请求资源未更新 |
400 | Bad Request | 非法请求 |
401 | Unauthorized | 请求未经授权 |
403 | Forbidden | 禁止访问 |
404 | Not Found | 没有找到页面 |
500 | Internal Server Error | 服务器内部错误 |
501 | Not Implemented | 服务器不支持实现请求功能 |
URLError和HTTPError中的属性及源码error.py:
"""Exception classes raised by urllib. The base exception class is URLError, which inherits from OSError. It
doesn't define any behavior of its own, but is the base class for all
exceptions defined in this package. HTTPError is an exception class that is also a valid HTTP response
instance. It behaves this way because HTTP protocol errors are valid
responses, with a status code, headers, and a body. In some contexts,
an application may want to handle an exception like a regular
response.
""" import urllib.response __all__ = ['URLError', 'HTTPError', 'ContentTooShortError'] class URLError(OSError):
# URLError is a sub-type of OSError, but it doesn't share any of
# the implementation. need to override __init__ and __str__.
# It sets self.args for compatibility with other OSError
# subclasses, but args doesn't have the typical format with errno in
# slot 0 and strerror in slot 1. This may be better than nothing.
def __init__(self, reason, filename=None):
self.args = reason,
self.reason = reason
if filename is not None:
self.filename = filename def __str__(self):
return '<urlopen error %s>' % self.reason class HTTPError(URLError, urllib.response.addinfourl):
"""Raised when HTTP error occurs, but also acts like non-error return"""
__super_init = urllib.response.addinfourl.__init__ def __init__(self, url, code, msg, hdrs, fp):
self.code = code
self.msg = msg
self.hdrs = hdrs
self.fp = fp
self.filename = url
# The addinfourl classes depend on fp being a valid file
# object. In some cases, the HTTPError may not have a valid
# file object. If this happens, the simplest workaround is to
# not initialize the base classes.
if fp is not None:
self.__super_init(fp, hdrs, url, code) def __str__(self):
return 'HTTP Error %s: %s' % (self.code, self.msg) def __repr__(self):
return '<HTTPError %s: %r>' % (self.code, self.msg) # since URLError specifies a .reason attribute, HTTPError should also
# provide this attribute. See issue13211 for discussion.
@property
def reason(self):
return self.msg @property
def headers(self):
return self.hdrs @headers.setter
def headers(self, headers):
self.hdrs = headers
源码中可以看到,URLError类中有reason属性,HTTPError类具有code属性,HTTPError可以继承父类URLError中的reason属性,而HTTPError是引起URLError的一个原因,即当触发HTTPError引起的URLError异常时,URLError是具有code和reason属性,而HTTPError一直具有code和reason属性。因此,可以使用hasattr()函数在使用前判断是否存在属性,进而通过状态码的存在判定异常URLError的原因与HTTPError是否有关。
import urllib.request
import urllib.error try:
urllib.request.urlopen("http://blog.csdn.net")
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
python爬虫之urllib库(二)的更多相关文章
- python爬虫之urllib库(一)
python爬虫之urllib库(一) urllib库 urllib库是python提供的一种用于操作URL的模块,python2中是urllib和urllib2两个库文件,python3中整合在了u ...
- python爬虫之urllib库(三)
python爬虫之urllib库(三) urllib库 访问网页都是通过HTTP协议进行的,而HTTP协议是一种无状态的协议,即记不住来者何人.举个栗子,天猫上买东西,需要先登录天猫账号进入主页,再去 ...
- python爬虫之urllib库介绍
一.urllib库 urllib是Python自带的一个用于爬虫的库,其主要作用就是可以通过代码模拟浏览器发送请求.其常被用到的子模块在Python3中的为urllib.request和urllib. ...
- python 爬虫之 urllib库
文章更新于:2020-03-02 注:代码来自老师授课用样例. 一.初识 urllib 库 在 python2.x 版本,urllib 与urllib2 是两个库,在 python3.x 版本,二者合 ...
- Python 爬虫之urllib库的使用
urllib库 urllib库是Python中一个最基本的网络请求库.可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据. urlopen函数: 在Python3的urlli ...
- python爬虫入门urllib库的使用
urllib库的使用,非常简单. import urllib2 response = urllib2.urlopen("http://www.baidu.com") print r ...
- python爬虫之urllib库
请求库 urllib urllib主要分为几个部分 urllib.request 发送请求urllib.error 处理请求过程中出现的异常urllib.parse 处理urlurllib.robot ...
- Python爬虫系列-Urllib库详解
Urllib库详解 Python内置的Http请求库: * urllib.request 请求模块 * urllib.error 异常处理模块 * urllib.parse url解析模块 * url ...
- python爬虫03 Urllib库
Urllib 这可是 python 内置的库 在 Python 这个内置的 Urllib 库中 有这么 4 个模块 request request模块是我们用的比较多的 就是用它来发起请求 所以我 ...
随机推荐
- wsl命令行
参考: https://docs.microsoft.com/en-us/windows/wsl/about 查看已安装 wslconfig /l /all 重装 wslconfig /u debia ...
- Spring Boot☞ 使用velocity渲染web视图
效果图: 代码 <!DOCTYPE html><html><head lang="en"> <meta charset="UTF ...
- python 数据清洗
前言 1. 删除重复 2. 异常值监测 3. 替换 4. 数据映射 5. 数值变量类型化 6. 创建哑变量 统计师的Python日记[第7天:数据清洗(1)] 前言 根据我的Python学习计划: N ...
- Mac下在zsh中配置adb命令
Mac下自带的终端默认黑白色的,对于一个技术宅来说不能忍啊.然后换成了iTerm,安装上了zsh,安装后界面如下: 这里写图片描述 但是常用的adb命令却找不到了,还向github上提了issue,下 ...
- Caused by: org.hibernate.HibernateException: Unable to build the default ValidatorFactory
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testAction': ...
- Ubuntu下安装配置java及环境变量
这里的办法不是在线安装,因为需要更新源(你懂的,费时费事~),so这里介绍在Ubuntu上手动下载安装配置Java环境变量 *系统:Ubuntu 16.4 1.下载jdk,直接用系统的Firefox浏 ...
- javascript高级程序设计读书笔记----严格模式
ECMAScript5最早引入“严格模式". 使用 "use strict"开启严格模式 function test(){ "use strict"; ...
- Vc6.0 编译发生致命链接错误 :不能打开exe的文件
错误: fatal error LNK1104: cannot open file "Debug/CeshiToolBar1.exe" 解决方法:打开任务管理器,找到对应的exe应 ...
- HTML中的内容总结
一.URL编码类型 对于Get方法,参数是直接通过URL传递的,那这个参数又是根据什么进行编码的呢?对于JSP网页,这个编码是通过第一句描述: <%@ page language="j ...
- Linq to Entities基础之需要熟知14个linq关键字(from,where,select,group,let,on,by...)
1.Linq基础 <1> 关键词: from,in,group,by,where..... MSDN上总结的有14个关键词法... from xxxx in xxxx select =&g ...