urllib.request优缺点
优点
- 将proxy,cookie,重定向等功能做成插件式,并对这些插件排序管理,用于在网络访问时各个功能按次使用
- 集成http、https、ftp等应用层协议
- 默认自动处理 http 300 系列重定向响应
- 采用【connection:close】方式来作为数据接收完成的信号,不再用底层的 http.client 的 【Content-Length】来作为数据接收完成的判断
缺点
- 【connection:close】是把双刃剑,每访问一次,就要建立-关闭一次连接,耗费资源
- 对 http 300 重定向的缺省处理,有时对爬虫来说并不需要重定向操作。如通过响应的报文头中的location便可以获取想要的信息
cookie切换
- 在此,有必要记录一下urllib.request的插件式工作原理。urllib.request发起请求的基础为OpenerDirector,由他管理着一系列插件,如proxyhandler,httpcookieprocessor,httpredirecthandler等,通过openerdirector.add_handler()插入,这些插件都有相应的序号,方便openerdirector按个调用。这些插件都维护着基本格式的方法接口,<protocol>_open(), <protocol>_error_<nnn>(), <protocol>_request(), <protocol>_response() 方法,openerdirector便是找这些插件调用这些方法。如httpredirectorhandler在重定向前需要http_error_30x()重构req以便再次访问
- openerdirector不止维护着一个handlers序列,还维护着四个集合用于后续open处理,分别为hand_open, hand_error process_request, process_response,此四个序列所关联的全是各handler插件
- python原生模块提供对http协议cookie的支持,在 http.cookiejar 中,在urllib.request.HttpCookieProcessor插件中封装cookiejar HTTPCookieProcessor(CookieJar()) ,提供api。
- 要在爬取过程中切换cookie,则只需要在HttpCookieProcessor插件的内置cookiejar实例在一定条件下清空所保存的cookie,该cookiejar便会重新获取cookie用于下次访问
def cookie_switch(self):
if hasattr(self, 'httpCookieProcessor'):
self.cookie_used_times += 1
if self.cookie_used_times > self.max_cookie_used_times+1:
self.httpCookieProcessor.cookiejar.clear()
self.cookie_used_times = 1
proxy切换
urllib.request中proxyhandler机制探索。
- ProxyHandler(proxies)实例化过程中,会生成http_open(req, proxy=proxyip,type=‘http’, meth=proxy_open)/https_open(req, proxy=proxyip,type=‘https’, meth=proxy_open)两个方法,这两个方法是proxyhandler功能要点,也是用于openerdirector调用的方法。其中proxy参数在方法生成时便以默认参数的形式给定,后面发生调用行为时不可更改。即代理ip与proxyhandler实例初始化强烈相关。
- 虽然proxyhandler是openerdirector的缺省插件,但是若无实际代理ip存在,便没有http_open/https_open方法,无法为openerdirector提供功能接口。
- 由上,要在爬取过程中切换代理ip,直接修改proxyhandler中的代理ip,由于其方法http_open()与代理ip强相关,没有提供直接切换代理ip的方法接口;若通过更换openerdirector维护序列中的proxyhandler,handlers里好替换,另外四个集合呢?
- 最终,找到了一个切换代理ip的方法,通过已有proxyhandler再次初始化的方法重置其维护的代理ip,重新初始化,便会重新创建其http_open()方法,顺利解决urllib.request中的代理ip切换问题。
def proxy_switch(self):
if hasattr(self, 'proxyHandler'):
self.proxy_used_times += 1
if self.proxy_used_times > self.max_proxy_used_times:
urllib2.ProxyHandler.__init__(self.proxyHandler, self.takeout_proxy()) # 什么时候切换代理ip?当代理ip使用次数达到上限时。
self.proxy_used_times = 1
对urllib.request照猫画虎
- 内置的urllib.request固然方便,但是他对爬虫来说最不应该错误在写死的connection:close,每访问一次建立一个连接,这主要对目标服务器资源是一笔巨大的消耗。为此,我模仿urllib.request插件式的思路。利用底层http.client,http.cookiejar构建出一个可以切换cookie,代理ip,并且保持长连接的模块,在广州阳光家缘原始轮子的楼栋销控表采集中运用。请求调度器accessorScheduler维护着一个用于访问的socketHandler,cookie管理的cookieHandler,代理管理的proxyHandler,这三者都有序号,用于顺序调用。
def get_source(self, method, url, headers, data=None):
faild_tried_accessed_times = 0
req = self.generate_request(method, url, headers, data)
resp = None
source = None
hosts = parse_netloc_to_hosts(req.headers['Host'])
while faild_tried_accessed_times < self.max_faild_tried_accessed_times:
# print(url)
if self.max_access_interval:
time.sleep(self.max_access_interval*random.random())
proxy = None
for step in self.accessor_queue:
if step == 1:
req = self.cookieHandler.add_cookie_to_request(req)
# print('have add cookie to header is : {0}'.format(req.get_header('Cookie')))
elif step == 2:
proxy = self.proxyHandler.get_proxy()
elif step == 3:
conn_hosts = hosts
if proxy:
conn_hosts = proxy
# conn_hosts = ('127.0.0.1', 8888)
# print('will build connection to : {0}'.format(conn_hosts))
self.socketHandler.build_connection(conn_hosts)
elif step == 4:
req.headers.update(req.unredirected_hdrs)
resp = self.socketHandler.request(req.get_method(), req.get_full_url(), req.headers, req.data)
# print(type(resp))
elif step == 5 and resp:
source_bytes = self.socketHandler.getsource(resp)
if source_bytes:
source = parse_source_bytes_to_str(source_bytes, dict(resp.getheaders()))
elif step == 6:
if req and resp:
self.cookieHandler.resolve_cookie_from_response(resp, req)
# print('will extract cookie to jar : {0}'.format(resp.getheader('Set-Cookie')))
if source:
break
else:
faild_tried_accessed_times += 1
return source
- 代理ip的切换在于建立连接目标的切换,上面step=3
本文详细介绍了urllib.request模块的优缺点,包括其对proxy和cookie的处理方式。讨论了如何在爬虫过程中切换cookie和proxy,并探讨了urllib.request在处理http 300重定向时的不足。最后,提出了一个模仿urllib.request的解决方案,以实现长连接、cookie和proxy的切换,以降低服务器资源消耗。
998

被折叠的 条评论
为什么被折叠?



