美文网首页python大法攻略
Scrapy+redis分布式爬虫(一、理论概念)

Scrapy+redis分布式爬虫(一、理论概念)

作者: 眼君 | 来源:发表于2020-09-11 09:01 被阅读0次

    scrapy的工作原理

    scrapy工作的步骤如下图所示:

    1. spiders获取的requests通过engine交给scheduler进行调度。
    2. engine从scheduler获得requests, 交给downloader进行下载。
    3. engine将downloader返回的response交给spiders进行解析。
    4. spiders从response中解析出items和requests后, 分别交给item pipelines和scheduler处理。

    理论基础

    正则表达式模式匹配

    xpath使用路径表达式在xml和html中进行导航。

    Xpath语法
    表达式                                说明 
    
    article                             选取所有aricle元素所有子节点
    
    /article                           选取根节点article
    
    article / a                         选取所有属于article子元素的a元素
    
    // div                              选取所有属于子元素的div元素(无论出现在文档任何地方)
    
    article // div                      选取所有属于article元素后代的div元素,不管它出现在article之下的任何位置
    
    //@class                            选取所有名为class的属性的节点
    
    /article/div[1]                    选取属于article子元素的第一个div
    
    /article/div[last()]               选取属于article子元素的最后一个 div元素
    
    /article/div[last()-1]             选取属于article子元素的倒数第二个div元素    
    
    //div[@lang]                        选取所有拥有lang属性的div元素
    
    //div[@lang = 'eng']                选取所有lang属性为eng的div元素
    
    /div/*                              选取div元素的所有子节点
    
    //*                                 选取所有元素
    
    //div[@*]                           选取所有带属性的div元素
    
    //div/a/|//div/p                    选取所有div元素的a和p元素
    
    //span|//ul                         选取所有的span和ul元素
    
    article/div/p|//ul                  选取所有属于article元素子元素div的子元素p以及所有的span元素
    
    //span[contains(@class,'vote-post-up')]        选取所有的class中含有vote-post-up的span子元素
    
    CSS选择器语法
    表达式                               说明
    
     *                                  选择所有节点
    
    #container                          选择id为container的节点
    
    .container                          选择所有class包含container的节点
    
    li  a                               选择li下的所有a节点
    
    ul + p                              选择ul后面的第一个p元素
    
    div#container   > ul                选择id为container的div的第一个ul子元素
    
    ul ~ p                              选取与ul相邻的所有p元素
    
    a[title]                            选取所有有title属性的a元素
    
    a[href="http://jobbole.com"]        选取所有href属性为http://jobbole.com的a元素
    
    a[href*="jobbole"]                  选取所有href属性包含jobbole的a元素
    
    a[href^ ="http"]                    选取所有href属性以http开头的a元素
    
    a[href$=".jpg"]                     选取所有href属性以.jpg结尾的a元素
    
    input[type=radio]:checked           选取选中的radio元素
    
    a[title]                            选取所有有title属性的a元素
    
    div:not(#container)                 选取所有id非container的div属性
    
    li:nth-child(3)                     选取第三个li元素
    
    tr:nth-child(2n)                    选取第偶数个tr
    
    a::text                             获取a标签中的文本内容
    
    a::attr(href)                       获取a标签中href属性的值
    
    

    深度优先和广度优先

    一般情况下, 我们将网站域名之间的关系看作是一个树结构, 对于树结构中各节点的顺序分为深度优先和广度优先:

    二叉树的深度优先算法实现
    def depth_tree(tree_node):
        if tree_node is not None:
            print(tree_node._data)
            if tree_node._left is not None:
                return depth_tree(tree_node._left)
            if tree_node._right is not None:
                return depth_tree(tree_node._right) 
    
    二叉树的广度优先算法实现
    def level_queue(root):
        """利用队列实现树的广度优先算法"""
        if root is None:
            return
        my_queue = []
        node = root
        my_queue.append(node)
        while my_queue:
            node = my_queue.pop(0)
            print(node.elem)
            if node.lchild is not None:
                my_queue.append(node.lchild)
            if node.rchild is not None:
                my_queue.append(node.rchild)
    
    

    创建一个scrapy项目

    我们先拿链家的二手房成交数据练个手, 先自行新建一个文件夹用于存储文件, 之后cd到该目录下, 新建一个scrapy项目:

    scrapy startproject ZiruSpider(工程名)
    

    用编译器打开项目,找到文件scrapy.cfg, 这个文件记录的是该项目的配置信息:

    # Automatically created by: scrapy startproject
    #
    # For more information about the [deploy] section see:
    # https://scrapyd.readthedocs.io/en/latest/deploy.html
    
    [settings]
    default = ZiruCrawler.settings
    
    [deploy]
    #url = http://localhost:6800/
    project = ZiruCrawler
    

    主目录下还有一个文件setting.py是项目的配置文件, 记录的是项目的一些配置信息:
    其中的robotstxt_obey记录的是本项目是否遵循robots协议, 为了提高爬虫有效性, 一般这里改成False。

    BOT_NAME = 'ZiruCrawler'
    
    SPIDER_MODULES = ['ZiruCrawler.spiders']
    NEWSPIDER_MODULE = 'ZiruCrawler.spiders'
    
    # Crawl responsibly by identifying yourself (and your website) on the user-agent
    #USER_AGENT = 'ZiruCrawler (+http://www.yourdomain.com)'
    
    # Obey robots.txt rules
    ROBOTSTXT_OBEY = False
    

    pipelines.py是记录数据存储相关信息的模块;
    middlewares.py是存放我们自己定义middlewares的模块;
    items.py是类似django中的form, 定义数据保存的格式;

    创建一个爬虫脚本

    主目录下一个spiders文件夹是用于存放针对某个网站的爬虫脚本的。
    至于这些脚本是如何生成的, 我打开项目根目录下,运行以下命令:

    cd ZiruSpider
    scrapy genspider lianjia(爬虫名)  hz.lianjia.com/chengjiao/(目标网站地址)
    

    这样我们就生成了一个名为lianjia.py的爬虫脚本文件, 专门用于 爬取hz.lianjia.com/chengjiao/。这个文件中start_urls中存放的就是这个爬虫开始爬取数据时使用到的第一个URL。

    创建调试脚本

    在最外层目录下创建一个用于调试的脚本文件main.py, scrapy调试的主要原理是通过脚本模拟在命令行执行命令:

    from scrapy.cmdline import execute
    
    import sys
    import os
    
    #将最外层目录路径放入系统目录下
    sys.path.append(os.path.dirname(os.path.abspath(__file__)))
    execute(["scrapy","crawl","lianjia"])
    

    运行以上脚本等价于在项目最外层目录下打开命令行运行以下命令:

    scrapy crawl lianjia(爬虫名,即对应的爬虫脚本下name = []中的名字)
    

    之后我们就可以通过断点的方式对main.py进行debug执行。
    如果在windows 下报错"ImportError: No module named 'win32api'",则需要先输入以下命令安装一个依赖包:

    pip3 install pypiwin32
    
    scrapy的shell模式调试

    打开终端执行以下命令:

    scrapy shell <需要解析页面的URL>
    

    通过这种方式可以使用shell对页面进行解析, 这样我们在编写爬虫, 解析页面时就可以用这个shell做检测。



    之后执行以下语句可以得到title元素中data的内容

    title.extract()
    

    如果访问URL时需要添加headers可以写如下代码:

    scrapy shell -s USER_AGENT="Mozilla/5.0 (Macintosh; Intel Mac OS X..." <需要解析页面的URL>
    

    scrapy也可以通过css选择器来使用:

    title = response.css('.entry-header')
    

    css里的::text 等价于xpath里的text()

    相关文章

      网友评论

        本文标题:Scrapy+redis分布式爬虫(一、理论概念)

        本文链接:https://www.haomeiwen.com/subject/darjektx.html