Python爬虫模块使用方法

Python爬虫模块使用

requests模块

Requests模块是在Python内置模块的基础上进行了高度的封装,主要用来发送HTTP网络请求,可以轻而易举的完成浏览器的任何操作。 Requests模块比urllib2模块更简洁。

使用步骤

  1. 可以直接使用python pip进行安装

     >>>pip install requests
    
  2. 导入模块

    import requests
    
  3. 定制请求头headers

    headers = {
        'Host': 'node16.sleap.com:8089',
        'Referer': 'http://node16.sleap.com:8089/leapid-admin/view/login.html?cb=http%3A%2F%2Fnode15.sleap.com%3A2017',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
    }
    r = requests.get(url, headers=headers)
    
  4. 发送请求

    #######r为Response对象,我们可以从这个对象中获取请求返回的信息。###########
    r = requests.get('https://api.github.com/events')
    r = requests.post('http://httpbin.org/post', data = {'key':'value'})
    r = requests.put('http://httpbin.org/put', data = {'key':'value'})
    r = requests.delete('http://httpbin.org/delete')
    r = requests.head('http://httpbin.org/get')
    r = requests.options('http://httpbin.org/get')
    
  5. 传递URL参数

    httpbin.org/get?key=val。

    #####Requests 允许你使用 params 关键字参数,以一个字符串字典来提供这些参数#####
    payload = {'key1': 'value1', 'key2': 'value2'}
    r = requests.get("http://httpbin.org/get", params=payload)
    

    通过打印输出该 URL,你能看到 URL 已被正确编码:

    >>> print(r.url)
    http://httpbin.org/get?key1=value1&key2=value2&key2=value3
    
  6. 响应内容

    Requests 会自动解码来自服务器的内容。大多数 unicode 字符集都能被无缝地解码。

    >>> r = requests.get('https://api.github.com/events')
    >>> r.text
    u'[{"repository":{"open_issues":0,"url":"https://github.com/...
    

    你可以找出 Requests 使用了什么编码,并且能够使用 r.encoding 属性来改变它:

    >>> r.encoding
    'utf-8'
    >>> r.encoding = 'ISO-8859-1'
    
  7. JSON响应内容

    Requests 中也有一个内置的 JSON 解码器,助你处理 JSON 数据:

    >>> r = requests.get('https://api.github.com/events')
    >>> r.json()
    [{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...
    

    如果 JSON 解码失败, r.json() 就会抛出一个异常。例如,响应内容是 401 (Unauthorized),尝试访问 r.json() 将会抛出 ValueError: No JSON object could be decoded 异常。

  8. 复杂的POST请求

    发送一些编码为表单形式的数据——非常像一个 HTML 表单。要实现这个,只需简单地传递一个字典给 data 参数。你的数据字典在发出请求时会自动编码为表单形式:

    >>> payload = {'key1': 'value1', 'key2': 'value2'}
    >>> r = requests.post("http://httpbin.org/post", data=payload)
    >>> print(r.text)
    {
      ...
      "form": {
        "key2": "value2",
        "key1": "value1"
      },
      ...
    }
    
  9. 响应状态码

    我们可以通过r.status_code检测响应状态码:

    >>> r = requests.get('http://httpbin.org/get')
    >>> r.status_code
    200
    
  10. 响应头

    >>> r.headers
    
  11. Cookie

    如果某个响应中包含一些 cookie,你可以快速访问它们:

    >>> url = 'http://example.com/some/cookie/setting/url'
    >>> r = requests.get(url)
    >>> r.cookies['example_cookie_name']
    'example_cookie_value'
    

    发送得到的cookie到服务器,可以使用cookie参数:

    >>> url = 'http://httpbin.org/cookies'
    >>> cookies = dict(cookies_are='working')
    >>> r = requests.get(url, cookies=cookies)
    >>> r.text
    '{"cookies": {"cookies_are": "working"}}'
    

    Cookie 的返回对象为 RequestsCookieJar,它的行为和字典类似,但接口更为完整,适合跨域名跨路径使用。你还可以把 Cookie Jar 传到 Requests 中:

    >>> jar = requests.cookies.RequestsCookieJar()
    >>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
    >>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
    >>> url = 'http://httpbin.org/cookies'
    >>> r = requests.get(url, cookies=jar)
    >>> r.text
    '{"cookies": {"tasty_cookie": "yum"}}'
    
  12. 会话对象

    会话对象让你能够跨请求保持某些参数。它也会在同一个 Session 实例发出的所有请求之间保持 cookie,所以如果你向同一主机发送多个请求,底层的 TCP 连接将会被重用,从而带来显著的性能提升。
    会话对象具有主要的 Requests API 的所有方法。
    跨请求保持一些 cookie:

    s = requests.Session()
    
    s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
    r = s.get("http://httpbin.org/cookies")
    
    print(r.text)
    # '{"cookies": {"sessioncookie": "123456789"}}'
    
  13. 请求与响应对象

    任何时候进行了类似requests.get()的调用,你都在做两件主要的事情。其一,你在构建一个Request对象, 该对象将被发送到某个服务器请求或查询一些资源。 其二,一旦requests得到一个从服务器返回的响应就会产生一个Response对象。该响应对象包含服务器返回的所有信息,也包含你原来创建的Request对象。
    如果想访问服务器返回给我们的响应头部信息,可以这样做:

    >>> r.headers
    

    如果想得到发送到服务器的请求的头部,我们可以简单地访问该请求,然后是该请求的头部:

    >>> r.request.headers
    

urllib模块

urllib 库用于操作网页 URL,并对网页的内容进行抓取处理。

urllib 包 包含以下几个模块:

  • urllib.request - 打开和读取 URL。
  • urllib.error - 包含 urllib.request 抛出的异常。
  • urllib.parse - 解析 URL。
  • urllib.robotparser - 解析 robots.txt 文件。

使用步骤

  1. 打开一个 URL

    urlopen ,然后使用 read() 函数获取网页的 HTML 实体代码。

    urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None,capath=None, cadefault=False, context=None)
    # url:url 地址。
    # data:发送到服务器的其他数据对象,默认为 None。
    # timeout:设置访问超时时间。
    # cafile 和 capath:cafile 为 CA 证书, capath 为 CA 证书的路径,使用 HTTPS 需要用到。
    # cadefault:已经被弃用。
    # context:ssl.SSLContext类型,用来指定 SSL 设置。
    # read() 是读取整个网页内容,我们可以指定读取的长度。
    
  2. 读取网页内容

    除了 read() 函数外,还包含以下两个读取网页内容的函数:

    #readline() - 读取文件的一行内容
    from urllib.request import urlopen
    myURL = urlopen("https://www.runoob.com/")
    print(myURL.readline()) #读取一行内容
    
    #readlines() - 读取文件的全部内容,它会把读取的内容赋值给一个列表变量。
    from urllib.request import urlopen
    myURL = urlopen("https://www.runoob.com/")
    lines = myURL.readlines()
    for line in lines:
        print(line) 
    
  3. 判断网页正常访问

    #我们在对网页进行抓取时,经常需要判断网页是否可以正常访问,这里我们就可以使用 getcode() 函数获取网页状态码,返回 200 说明网页正常,返回 404 说明网页不存在:
    import urllib.request
    
    myURL1 = urllib.request.urlopen("https://www.runoob.com/")
    print(myURL1.getcode())   # 200
    
    try:
        myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html")
    except urllib.error.HTTPError as e:
        if e.code == 404:
            print(404)   # 404
    
  4. 抓取的网页保持到本地

    #如果要将抓取的网页保持到本地,可以使用 Python3 File write() 方法
    from urllib.request import urlopen
    
    myURL = urlopen("https://www.runoob.com/")
    f = open("runoob_urllib_test.html", "wb")
    content = myURL.read()  # 读取网页内容
    f.write(content)
    f.close()
    #执行以上代码,在本地就会生成一个 runoob_urllib_test.html 文件,里面包含了网页的内容
    
  5. URL 的编码与解码

    #编码与解码可以使用 urllib.request.quote() 与 urllib.request.unquote()方法
    import urllib.request
    
    encode_url = urllib.request.quote("https://www.runoob.com/")  # 编码
    print(encode_url)
    
    unencode_url = urllib.request.unquote(encode_url)    # 解码
    print(unencode_url)
    
    #out
    https%3A//www.runoob.com/
    https://www.runoob.com/
    
  6. 模拟头部信息

    #我们抓取网页一般需要对 headers(网页头信息)进行模拟,这时候需要使用到urllib.request.Request 类
    
    class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
    
    #url:url 地址。
    #data:发送到服务器的其他数据对象,默认为 None。
    #headers:HTTP 请求的头部信息,字典格式。
    #origin_req_host:请求的主机地址,IP 或域名。
    #unverifiable:很少用整个参数,用于设置网页是否需要验证,默认是False。。
    #method:请求方法, 如 GET、POST、DELETE、PUT等。
    
  7. 异常

    urllib.error 模块为 urllib.request 所引发的异常定义了异常类,基础异常类是 URLError。

    urllib.error 包含了两个方法,URLError 和 HTTPError。

    URLError 是 OSError 的一个子类,用于处理程序在遇到问题时会引发此异常(或其派生的异常),包含的属性 reason 为引发异常的原因。

    HTTPError 是 URLError 的一个子类,用于处理特殊 HTTP 错误例如作为认证请求的时候,包含的属性 code 为 HTTP 的状态码, reason 为引发异常的原因,headers 为导致 HTTPError 的特定 HTTP 请求的 HTTP 响应头。

    #对不存在的网页抓取并处理异常
    import urllib.request
    import urllib.error
    
    myURL1 = urllib.request.urlopen("https://www.runoob.com/")
    print(myURL1.getcode())   # 200
    
    try:
        myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html")
    except urllib.error.HTTPError as e:
        if e.code == 404:
            print(404)   # 404
    
  8. 解析

    urllib.parse 用于解析 URL

    urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
    #urlstring 为 字符串的 url 地址,scheme 为协议类型
    #allow_fragments 参数为 false,则无法识别片段标识符。相反,它们被解析为路径,参数或查询组件的一部分,并 fragment 在返回值中设置为空字符串。
    
    from urllib.parse import urlparse
    
    o = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
    print(o)
    
    #out
    ParseResult(scheme='https', netloc='www.runoob.com', path='/', params='', query='s=python+%E6%95%99%E7%A8%8B', fragment='')
    #从结果可以看出,内容是一个元组,包含 6 个字符串:协议,位置,路径,参数,查询,判断
    
    #还可以直接读取协议内容
    from urllib.parse import urlparse
    
    o = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
    print(o.scheme)
    
    #out
    https
    

    urllib.robotparser 用于解析 robots.txt 文件。

    robots.txt(统一小写)是一种存放于网站根目录下的 robots 协议,它通常用于告诉搜索引擎对网站的抓取规则。

    urllib.robotparser 提供了 RobotFileParser 类,这个类提供了一些可以读取、解析 robots.txt 文件的方法。

    class urllib.robotparser.RobotFileParser(url='')
    
    #set_url(url) 设置 robots.txt 文件的 URL。
    
    #read() 读取 robots.txt URL 并将其输入解析器。
    
    #parse(lines) 解析行参数。
    
    #can_fetch(useragent, url) 如果允许 useragent 按照被解析 robots.txt 文件中的规则来获取 url 则返回 True。
    
    #mtime() 返回最近一次获取 robots.txt 文件的时间。 这适用于需要定期检查 robots.txt 文件更新情况的长时间运行的网页爬虫。
    
    #modified() 将最近一次获取 robots.txt 文件的时间设置为当前时间。
    
    #crawl_delay(useragent) 为指定的 useragent 从 robots.txt 返回 Crawl-delay 形参。 如果此形参不存在或不适用于指定的 useragent 或者此形参的 robots.txt 条目存在语法错误,则返回 None。
    
    #request_rate(useragent) 以 named tuple RequestRate(requests, seconds) 的形式从 robots.txt 返回 Request-rate 形参的内容。 如果此形参不存在或不适用于指定的 useragent 或者此形参的 robots.txt 条目存在语法错误,则返回 None。
    
    #site_maps() - 以 list() 的形式从 robots.txt 返回 Sitemap 形参的内容。 如果此形参不存在或者此形参的 robots.txt 条目存在语法错误,则返回 None。
    

高效爬虫

python里面共有进程、线程、协程三个层次概念,爬虫就是选择:单线程爬取,单线程+协程爬取,多线程爬取,多线程 + 协程爬取,多进程爬取,多进程 + 协程爬取6种组合方案。

存在依赖关系的协程之间是不能够被并发执行的,不存在依赖关系的协程之间是能够被并发执行的。

由于GIL锁的存在,使得线程没法并行执行,只能并发执行。而在并发的情况下,协程的创建、切换开销远远小于线程。所以使用协程而不是使用线程在Python里面是更优的解决方案。

最高效的爬取方案?答案是: 多进程 + 协程。

协程的方案肯定要比多线程快,因为协程的切换开销非常之小。而且协程的并发度可以非常高。我们一般开线程也就几十个线程,协程的并发度可以达到999个。但协程的缺点就是没法并行运行。

所以多进程 + 协程的方案既利用了并行,又利用了并发。完美了利用了多核,同时又让每一个线程的时间片被充分的利用。

posted @ 2021-08-28 14:09  苓渊  阅读(227)  评论(0编辑  收藏  举报