IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Python 简单爬虫

    Fish (fsh267@gmail.com)发表于 2016-01-26 00:00:00
    love 0

    什么是爬虫


    爬虫指的系统性抓取网络页面的网络机器人。原理图如下:

    crawler

    上图涉及了爬虫的任务调度控制,多线程,存储机制等,本文不会涉及。

    我们从最简单的故事谈起,当你浏览一个网站时, 发现上面的图片比较有意思,会右键保存下来,当人为操作过多时, 就会想办法自动化实现。

    首先是图片的保存, 我们知道直接使用linux 命令 curl -O http://img-url 就可以下载图片;
    那么如何获取图片地址呢, 很明显图片的链接地址存放在页面的源码中, command + u 就可以查看到页面的 source code, curl http://site-url 能获取到页面源码, 图片地址一般的格式为 </img> , 很容易就能筛选出来。

    上面分为三个部分, 获取页面代码, 解析页面代码, 存储&&展示。因此, 本人对爬虫的理解如下:

    • 打开网页
    • 解析网页
    • 重复上两步,将数据保存下来

    回到最开始的爬虫原理图, 在大规模网页爬取时,考虑到性能问题,会引入多线程等集群化抓取, 比如rq ; 已经爬过的页面不能从复爬,考虑到去重复问题, 会引入个 hash 或者更高级的 Bloom Filter; 数据的保存和抽取,丢到 MogoDB 中。 这样上图中的内容都包括了。

    举个例子

    不忘初衷,以爬妹子图 为例,简单说明一下简单爬虫的需要用到的知识。

    import os
    from urllib.request import urlopen, urlretrieve
    import re
    import time
    import sys
    
    
    def get_girls(url):
        page_source = urlopen(url).read().decode('GBK')
        pattern = r'<img alt="\S+" src="(\S+)" /><br />'
        img_urls = re.findall(pattern, page_source)
        for img_url in img_urls:
            img_name = sys.path[0] + os.sep + str(time.time()) + '.jpg'
            urlretrieve(img_url, filename=img_name)
    
    get_girls('http://www.meizitu.com/a/5284.html')

    函数 get_girls 里面, 使用到了 urllib 与 re 正则库, 稍后介绍, 执行过程如代码所述:

    1. urlopen() 将页面源码拉下来
    2. re.findall(pattern, source) 匹配到图片地址
    3. urlretrieve() 下载到本地

    随便输入几个地址执行下: girls

    很简单有趣吧~ 如果只是获取到图片地址,可直接在交互命令行搞

    >>> url = 'http://www.meizitu.com/a/5284.html'
    >>> page_source = str(urlopen(url).read())
    >>> img_urls = re.findall(r'<img alt="\S+" src="(\S+)" /><br />', page_source)
    >>> img_urls
    ['http://pic.meizitu.com/wp-content/uploads/2016a/01/21/01.jpg', 'http://pic.meizitu.com/wp-content/uploads/2016a/01/21/02.jpg', 'http://pic.meizitu.com/wp-content/uploads/2016a/01/21/03.jpg', 'http://pic.meizitu.com/wp-content/uploads/2016a/01/21/04.jpg', 'http://pic.meizitu.com/wp-content/uploads/2016a/01/21/05.jpg', 'http://pic.meizitu.com/wp-content/uploads/2016a/01/21/06.jpg', 'http://pic.meizitu.com/wp-content/uploads/2016a/01/21/07.jpg']
    

    页面源码拉取, 解析html, 获取数据,以上就是简单 Python 爬虫介绍。针对解析这一部分,有很多开源的库可以玩,非常有意思~

    Python 爬虫基本库

    Python urllib

    urllib 库是 python Http 协议的一个封装, 爬虫用到的网络请求操作, 在 urllib.requet 中。详情用法看文档, 常见的简单用法如下:

    读取网页 URL 可以是本地文件, ftp 地址等

    from urllib.request import urlopen, urlretrieve, Request, HTTPBasicAuthHandler, build_opener, install_opener
    res = urlopen('https://www.alipay.com/')
        print(res.read(100))
    
    # 指定编码
    with urlopen('https://www.alipay.com/') as res:
        print(res.read(300).decode('utf-8'))

    请求 CGI 端口

    req = Request(url='http://staff.washington.edu/corey/info.cgi', data=None)
    with urlopen(req) as f:
        print(f.read())

    官方文档给出的基本 Http 验证

    # Create an OpenerDirector with support for Basic HTTP Authentication...
    auth_handler = HTTPBasicAuthHandler()
    auth_handler.add_password(realm='PDQ Application',
                              uri='https://mahler:8092/site-updates.py',
                              user='klem',
                              passwd='kadidd!ehopper')
    opener = build_opener(auth_handler)
    # ...and install it globally so it can be used with urlopen.
    install_opener(opener)
    urlopen('http://www.example.com/login.html')

    使用 代理方式验证请求

    proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.example.com:3128/'})
    proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
    proxy_auth_handler.add_password('realm', 'host', 'username', 'password')
    
    opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
    # This time, rather than install the OpenerDirector, we use it directly:
    opener.open('http://www.example.com/login.html')

    保存到本地

    urlretrieve('https://alipay.com', '/tmp/index.html')

    Python 正则

    爬虫的第二个阶段, 用正则解析源代码。 正则语法很有意思, 写多了就不利于理解, 因此爬虫的解析库发展的多种多样, 基本原理还是基于 re 库。 具体的使用, 还是用 DOM 解析库比较方便, 当没辙时, 不得不回到正则大法~

    re.search re.match re.findall 的基本使用如下, 详细的使用可以看看Python正则表达式指南

    re.findall

    import re
    
    relink = '<a href="(.*)">(.*)</a>'
    info = '<a href="http://www.google.com">google</a>'
    cinfo = re.findall(relink, info)
    print(cinfo)
    # output: [('http://www.google.com', 'google')]

    re.match

    尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match() 就返回none。。

    line = "Google are much better than baidu."
    
    matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
    
    if matchObj:
        print("matchObj.group() : ", matchObj.group())
        print("matchObj.group(1) : ", matchObj.group(1))
        print("matchObj.group(2) : ", matchObj.group(2))
    else:
        print("No match!!")
    
    # [('http://www.google.com', 'google')]
    # matchObj.group() :  Google are much better than baidu.
    # matchObj.group(1) :  Google
    # matchObj.group(2) :  much

    re.search

    re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

    matchObj = re.match(r'Gogle', line, re.M | re.I)
    if matchObj:
        print("match --> matchObj.group() : ", matchObj.group())
    else:
        print("No match!!")
    
    matchObj = re.search(r'Google', line, re.M | re.I)
    if matchObj:
        print("search --> matchObj.group() : ", matchObj.group())
    else:
        print("No match!!")
    
    # No match!!
    # search --> matchObj.group() :  Google

    Python 正则字典

    最后, 贴一张 Python 支持的表达式元字符:

    x



沪ICP备19023445号-2号
友情链接