zoukankan      html  css  js  c++  java
  • 爬虫开发python工具包介绍 (1)

    本文来自网易云社区

    作者:王涛


    本文大纲:

    • 简易介绍今天要讲解的两个爬虫开发的python库

    • 详细介绍 requests库及函数中的各个参数

    • 详细介绍 tornado 中的httpcilent的应用

    • 总结

    目标:了解python中常用的快速开发爬虫的工具包。

    基础:    python的基础语法(2.7)

    Here we go!

    简易爬虫:我把一次性代码称为简易爬虫,这些爬虫是定制化的,不能通用。不像爬虫框架,通过配置就可以实现一个新的抓取需求。对于入门的盆友来讲,本篇文章基本可以满足你的需求。如果有对框架感兴趣的盆友,了解了本文的tornado,对于你了解pyspider这个框架也是有好处的。(Pyspdier使用了tornado框架)

    一、简介requests与tornado

    随着大数据、人工智能、机器学习的发展,python语言的编程地位保持着持续提升。其它方面的功能暂且不表(因为我不知道),我们来谈谈python在爬虫方面的表现。
    image

    1、requests 基础

    相信想快速上手爬虫的人都会选择python,并且选择requests库,请问获取百度首页源码要几步?
    答:三步
    第一步:下载和安装python
    第二步:pip 安装 requests库
    第三步:执行 python -c 'import requests; print requests.get("http://www.baidu.com").content'

    python -c 'import requests; print requests.get("http://www.baidu.com").content'<!DOCTYPE html>
    <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div <div <div <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span ><input id=kw name=wd value maxlength=255 autocomplete=off autofocus></span><span ><input type=submit id=su value=百度一下 ></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews <a href=http://www.hao123.com name=tj_trhao123 <a href=http://map.baidu.com name=tj_trmap <a href=http://v.baidu.com name=tj_trvideo <a href=http://tieba.baidu.com name=tj_trtieba <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" >登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a>  <a href=http://jianyi.baidu.com/ <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
    2、requests高效抓取

    高效抓取,那我们把串行改成并行。一谈并发,大家就想到多线程,多进程。

    但是大家知道,由于Ptyhon的解释器在执行的时候用了一把大锁GIL保证解释器(或者是python vm)在解释执行的时候只有一个线程得到调度,所以CPython事实上是伪多线程的,也就是本质上还是单线程。 注: GIL存在于CPython中,Jython没有这个限制(http://www.jython.org/jythonbook/en/1.0/Concurrency.html)

    image

    为了程序简单,就直接多线程运行了,毕竟Python自带的大多数数据结构是线程安全的(list,dict,tuple等),你可以不用考虑竞争给代码带来的复杂性。

    协程这个概念在很多编程语言中都已经支持了。python中通过yield关键字来实现协程,今天再给大家介绍一款基于协程的异步非阻塞框架 tornado. 使用它来实现网络请求,相比于多线程的requests更高效。

    3、tornado简介

    在介绍tornado之前,我们简单介绍一下协程的概念。

    3.1 协程

    在单线程的前提条件下:
    面向过程的编程中,我们会把一些代码块封装成一个函数,这个函数的特点:一个入口,一个出口.当我们调用一个函数时,会等它结束了才能继续执行后续的代码。 而协程在单线程的条件下,一个函数可以多次进入,多次返回,我们在调用协程函数的时候,可以在它的中断点暂时返回去执行其它的协程函数。(这有点像多线程,某一线程阻塞,CPU会调度其它线程)。

    下面给一段代码看一下运行效果,逻辑很简单,我们把show_my_sleep向IOLoop中添加了四次,每次入参不同。 show_my_sleep中打印信息,休眠,打印信息。根据结果,我们可以看到show_my_sleep函数在yield 语句进入休眠,暂时交出了运行权,等休眠结束后,从yield语句后开始继续执行。

    import randomfrom tornado.ioloop import IOLoopfrom tornado import gen@gen.coroutinedef show_my_sleep(idx):
        interval = random.uniform(5,20)    print "[{}] is going to sleep {} seconds!".format(idx, interval)    yield gen.sleep(interval)    # 此处会作为中断点,交出代码运行权
        print "[{}] wake up!!".format(idx)def main():
        io_loop = IOLoop.current()
        io_loop.spawn_callback(show_my_sleep, 1)  # 下一次循环的时候调度这个函数
        io_loop.spawn_callback(show_my_sleep, 2)
        io_loop.spawn_callback(show_my_sleep, 3)
        io_loop.spawn_callback(show_my_sleep, 4)
        io_loop.start()if __name__ == "__main__":
        main()

    结果:

    [1] is going to sleep 5.19272014406 seconds![2] is going to sleep 9.42334286914 seconds![3] is going to sleep 5.11032311172 seconds![4] is going to sleep 13.0816614451 seconds![3] wake up!![1] wake up!![2] wake up!![4] wake up!!
    3.2 Tornado 简介

    [译:https://www.tornadoweb.org/en/stable/guide/intro.html]

    Tornado 是基于Python实现的异步网络框架,它采用非阻塞IO,可以支持成千上万的并发访问量,
    所以非常适合于长轮询和Websocket, 以及其它需要持久连接的应用场景。Tornado 主要包含四个部分:- web框架,包括了RequestHandler(它可以用来创建WEB应用和各种支持的类)- 客户端、服务端侧的HTTP实现(包括HttpServer 和AsyncHttpClient)- 包含了 IOLoop和IOStream 的异步网络库,它们作为HTTP组件的内置块并且可以用来实现其它协议。- 协程库(tornado.gen),它使异步代码写起来比链式回调更直接。Tornado WEB框架和HTTP server 在一起可以作为WSGI的全栈替代。
    在WSGI容器里可以使用Tornado web框架,也可以用Http server 作为其它WSGI框架的容器,不过任意一种组合都是有缺陷的。
    为了充分发挥tornado的优势 ,你需要使用tornado 的web框架和http server.

    我们在这里主要借用tornado的 httpclient和协程库,来实现单线程下并发网络请求。
    Here, show you the code!

    import tracebackfrom tornado.ioloop import IOLoopfrom tornado import genfrom tornado.curl_httpclient import CurlAsyncHTTPClientfrom tornado.httpclient import HTTPRequest@gen.coroutinedef fetch_url(url):
        """抓取url"""
        try:
            c = CurlAsyncHTTPClient()  # 定义一个httpclient
            req = HTTPRequest(url=url)  # 定义一个请求
            response = yield c.fetch(req)  # 发起请求
            print response.body
            IOLoop.current().stop()  # 停止ioloop线程
        except:        print traceback.format_exc()def main():
        io_loop = IOLoop.current()
        io_loop.spawn_callback(fetch_url, "http://www.baidu.com")  # 添加协程函数到Ioloop循环中
        io_loop.start()if __name__ == "__main__":
        main()
    4、tornado并发

    这里简单讲,就是通过向ioloop中添加回调,来实现多个回调的并行调用。

    def main():
        io_loop = IOLoop.current()
        io_loop.spawn_callback(fetch_url, "http://www.baidu.com")  # 下一次循环的时候调度这个函数
        '''
        io_loop.spawn_callback(fetch_url, url1)  
        ... ...
        io_loop.spawn_callback(fetch_url, urln) 
        '''
        io_loop.start()if __name__ == "__main__":
        main()

    简单介绍过两个应用包后,来详细介绍一下关键函数及参数。

    二、requests 关键函数及参数

    我们利用requests开发爬虫时,主要会用到 get,post 方法,另外,为了应对反爬虫策略,会添加一些自定义的http头信息,我们从这个应用角度介绍一下requests的两个关键函数get和post。
    函数定义:

    def get(url, params=None, **kwargs):
        """Sends a GET request.
    
        :param url: URL for the new :class:`Request` object.
        :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """
    
        kwargs.setdefault('allow_redirects', True)    return request('get', url, params=params, **kwargs)
    def post(url, data=None, json=None, **kwargs):
        """Sends a POST request.
    
        :param url: URL for the new :class:`Request` object.
        :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
        :param json: (optional) json data to send in the body of the :class:`Request`.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """
    
        return request('post', url, data=data, json=json, **kwargs)

    我们可以看到,requests的get,post方法都会 调用 request函数,request函数定义如下:

        def request(self, method, url,        params=None,
            data=None,
            headers=None,
            cookies=None,
            files=None,
            auth=None,
            timeout=None,
            allow_redirects=True,
            proxies=None,
            hooks=None,
            stream=None,
            verify=None,
            cert=None,
            json=None):
            """Constructs a :class:`Request <Request>`, prepares it and sends it.
            Returns :class:`Response <Response>` object.
    
            :param method: method for the new :class:`Request` object.
            :param url: URL for the new :class:`Request` object.
            :param params: (optional) Dictionary or bytes to be sent in the query          
              string for the :class:`Request`.
            :param data: (optional) Dictionary, bytes, or file-like object to send         
               in the body of the :class:`Request`.
            :param json: (optional) json to send in the body of the
                :class:`Request`.
            :param headers: (optional) Dictionary of HTTP Headers to send with the
                :class:`Request`.
            :param cookies: (optional) Dict or CookieJar object to send with the
                :class:`Request`.
            :param files: (optional) Dictionary of ``'filename': file-like-objects``         
               for multipart encoding upload.
            :param auth: (optional) Auth tuple or callable to enable
                Basic/Digest/Custom HTTP Auth.
            :param timeout: (optional) How long to wait for the server to send
                data before giving up, as a float, or a :ref:`(connect timeout,
                read timeout) <timeouts>` tuple.
            :type timeout: float or tuple
            :param allow_redirects: (optional) Set to True by default.
            :type allow_redirects: bool
            :param proxies: (optional) Dictionary mapping protocol or protocol and
                hostname to the URL of the proxy.
            :param stream: (optional) whether to immediately download the response
                content. Defaults to ``False``.
            :param verify: (optional) whether the SSL cert will be verified.
                A CA_BUNDLE path can also be provided. Defaults to ``True``.
            :param cert: (optional) if String, path to ssl client cert file (.pem).
                If Tuple, ('cert', 'key') pair.
            :rtype: requests.Response
            """



    网易云免费体验馆,0成本体验20+款云产品! 

    更多网易研发、产品、运营经验分享请访问网易云社区


    相关文章:
    【推荐】 Android标题栏(1)
    【推荐】 移动端爬虫工具与方法介绍

  • 相关阅读:
    【NOIP 2003】 加分二叉树
    【POJ 1655】 Balancing Act
    【HDU 3613】Best Reward
    【POJ 3461】 Oulipo
    【POJ 2752】 Seek the Name, Seek the Fame
    【POJ 1961】 Period
    【POJ 2406】 Power Strings
    BZOJ3028 食物(生成函数)
    BZOJ5372 PKUSC2018神仙的游戏(NTT)
    BZOJ4836 二元运算(分治FFT)
  • 原文地址:https://www.cnblogs.com/163yun/p/9729483.html
Copyright © 2011-2022 走看看