python大法攻略

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

2020-09-11  本文已影响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()

上一篇 下一篇

猜你喜欢

热点阅读