urllib.request优缺点和cookie及proxy切换

本文详细介绍了urllib.request模块的优缺点,包括其对proxy和cookie的处理方式。讨论了如何在爬虫过程中切换cookie和proxy,并探讨了urllib.request在处理http 300重定向时的不足。最后,提出了一个模仿urllib.request的解决方案,以实现长连接、cookie和proxy的切换,以降低服务器资源消耗。
摘要由CSDN通过智能技术生成
urllib.request优缺点
优点
  1. 将proxy,cookie,重定向等功能做成插件式,并对这些插件排序管理,用于在网络访问时各个功能按次使用
  2. 集成http、https、ftp等应用层协议
  3. 默认自动处理 http 300 系列重定向响应
  4. 采用【connection:close】方式来作为数据接收完成的信号,不再用底层的 http.client 的 【Content-Length】来作为数据接收完成的判断
缺点
  1. 【connection:close】是把双刃剑,每访问一次,就要建立-关闭一次连接,耗费资源
  2. 对 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值