天天看点

Scrapy对接Selenium(说明在哪里进行对接为什么在这里):小猪短租网实战分析1. 新建项目2. 创建 Spider3. 网页的分析和自己爬取数据的确定4. 定义Item5. 构造 Request 请求列表6. 对接 Selenium (说明在哪里进行对接为什么在这里)7. 对页面进行解析8. 将数据存入数据库当中(Item Pipeline)9. 运行10. 运行结果

在没有系统学习框架进行爬虫的时候,已经可以使用selenium对动态渲染的网页和Ajax加载数据的网页进行爬取,但代码的整体逻辑在于自己对于方法的认识编写和使用,没有很强的逻辑框架性,在自学Scrapy框架的时候也学到对于Selenium的对接,最近进行了学习,现在和大家分享,有什么不足或错误的地方请评论或私信哟😁

使用selenium对网页抓取的原理在于,使用selenium模拟登陆浏览器进行抓取,不需要关心页面后台发生的请求,也不需要分析页面渲染过程,只需要关注页面最终结果即可,在进行网页跳转的时候,也只需要关心URL的变化规律,从而来构造请求列表来重复进行请求,也不需要关心如何去构造请求头。

Scrapy对接Selenium

  • 1. 新建项目
  • 2. 创建 Spider
  • 3. 网页的分析和自己爬取数据的确定
  • 4. 定义Item
  • 5. 构造 Request 请求列表
  • 6. 对接 Selenium (说明在哪里进行对接为什么在这里)
    • 6.1 启动自己所编写的 Downloader Middlewares
  • 7. 对页面进行解析
  • 8. 将数据存入数据库当中(Item Pipeline)
    • 8.1 定义自己的 Item Pipeline
    • 8.2 启动Item Pipeline
  • 9. 运行
  • 10. 运行结果

1. 新建项目

scrapy startproject scrapyselenium(项目名)
           

2. 创建 Spider

直接用Pycharm打开上一步所创建的项目,在最下面的Terminal处执行该命令:

scrapy genspider xiaozhu www.xiaozhu.com
           

3. 网页的分析和自己爬取数据的确定

目标网页URL(第一页):

url = 'https://cq.xiaozhu.com/search-duanzufang-p0-0/'
           

这个网页不是小猪短租的官网,这是在选择了地点(我选地点是重庆)后出现的页面的URL,因为我是为了去熟悉使用并了解Scrapy对接selenium,所以就直接偷懒选择了固定地点后的页面去进行分析。

Scrapy对接Selenium(说明在哪里进行对接为什么在这里):小猪短租网实战分析1. 新建项目2. 创建 Spider3. 网页的分析和自己爬取数据的确定4. 定义Item5. 构造 Request 请求列表6. 对接 Selenium (说明在哪里进行对接为什么在这里)7. 对页面进行解析8. 将数据存入数据库当中(Item Pipeline)9. 运行10. 运行结果
Scrapy对接Selenium(说明在哪里进行对接为什么在这里):小猪短租网实战分析1. 新建项目2. 创建 Spider3. 网页的分析和自己爬取数据的确定4. 定义Item5. 构造 Request 请求列表6. 对接 Selenium (说明在哪里进行对接为什么在这里)7. 对页面进行解析8. 将数据存入数据库当中(Item Pipeline)9. 运行10. 运行结果

由于是使用selenium进行可见可爬,所以不需要进行一系列的关于Request和Response请求的分析,转向寻找URL变化的规律,从而来构建Request的请求列表:

https://cq.xiaozhu.com/search-duanzufang-p0-0/
https://cq.xiaozhu.com/search-duanzufang-p1-0/
https://cq.xiaozhu.com/search-duanzufang-p2-0/
           

可以发现它的变化仅仅在于p0,p1的变化,用来控页数,接着我们就来看看自己所要的信息在哪,这里不建议直接f12去查看源代码,这个是辅助查询,主要代码依据是在服务器返回的请求响应中去查看源代码,源代码很可能在第一个响应中:

Scrapy对接Selenium(说明在哪里进行对接为什么在这里):小猪短租网实战分析1. 新建项目2. 创建 Spider3. 网页的分析和自己爬取数据的确定4. 定义Item5. 构造 Request 请求列表6. 对接 Selenium (说明在哪里进行对接为什么在这里)7. 对页面进行解析8. 将数据存入数据库当中(Item Pipeline)9. 运行10. 运行结果

并发现每一个房子的相关信息都存在 li 标签,class为current的标签当中,然后我就开始下一步的分析。

4. 定义Item

为要爬取的数据进行字段的定义。

import scrapy
from scrapy import Field


class HouseItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    house_name = Field()
    #location = Field()
    house_price = Field()
    house_href = Field()
    house_size = Field()
           

5. 构造 Request 请求列表

根据URL连接变化的规律来在 Spider中进行构造:

#这里ragne函数代表了页数的变化,为了测试,我这里只定义了一页的数据
    def start_requests(self):
        for i in range(1):
            i = str(i)
            url = 'https://cq.xiaozhu.com/search-duanzufang-p' + i + '-0/'
            yield Request(url=url,callback=self.parse)
           

6. 对接 Selenium (说明在哪里进行对接为什么在这里)

在构造完请求列表后,就要对这些请求进行抓取,从Scrapy整体框架和数据流的流向进行分析,当引擎从Scheduler中调度出请求后,请求将会被发往Downloader进行下载,在被下载之前会经过 Downloader Middleware下载器中间件进行请求的处理,我们变可以在这里对请求进行拦截,处理这个请求,使用Selenium对请求进行处理,最后返回HttpResponse请求,直接跳过下载器,直接交给Spider进行处理。

要先对这个请求进行拦截,我们需要在 middleware.py 中进行代码的编写,定义自己的中间类并进行启动,因为是处理到达下载器之前的Request请求,所以需要重写 process_request() 方法。

对于Scrapy项目运行数据流总览 AND 几个重要的组件、中间件分析,我的这篇博文已经给出:

https://blog.csdn.net/zc666ying/article/details/106601578
           
# 因为目的是测试并了解对接Selenium,并未做出任何模拟的点击,简单明了直接获取网页源码并返回
class SeleniumMiddleware(object):
    def process_request(self,request,spider):
        driver = webdriver.Chrome()
        #driver.maximize_window()
        driver.get(request.url)
        time.sleep(3)
        text = driver.page_source
        driver.quit()


        # https://doc.scrapy.org/en/latest/topics/request-response.html
        # 查看 HtmlResponse 对象结构
        return HtmlResponse(url=request.url,encoding='utf-8',body=text,request=request)
           

6.1 启动自己所编写的 Downloader Middlewares

在 settings.py 中进行设置:

DOWNLOADER_MIDDLEWARES = {
    'scrapyselenium.middlewares.SeleniumMiddleware':543,
}
           

7. 对页面进行解析

由于上面说到所返回的Response对象会直接给Spider,所以直接编写解析函数 parse():

def parse(self, response):
        house_name = response.xpath('//img[@class="lodgeunitpic"]/@title').extract()
        house_price = response.xpath('//span[@class="result_price"]//i/text()').extract()
        house_size = response.xpath('//em[@class="hiddenTxt"]/text()').extract()
        house_href = response.xpath('//a[contains(@target,"_blank") and @class="resule_img_a"]/@href').extract()
        for i in range(len(house_name)):
            item = HouseItem(
                house_name = house_name[i],
                house_price = house_price[i],
                house_size = house_size[i],
                house_href = house_href[i]
            )
            yield item
           

8. 将数据存入数据库当中(Item Pipeline)

8.1 定义自己的 Item Pipeline

import pymysql


class PymysqlPipeline(object):
    #连接数据库
    def __init__(self):
        self.connect = pymysql.connect(
            host = 'localhost',
            database = 'xiaozhu_house',
            user = 'root',
            password = '123456',
            charset = 'utf8',
            port = 3306
        )
        # 创建游标对象
        self.cursor = self.connect.cursor()

    # 此方法是必须要实现的方法,被定义的 Item Pipeline 会默认调用这个方法对 Item 进行处理
    def process_item(self,item,spider):
        cursor = self.cursor
        sql = 'insert into house_information(house_name,house_price,house_size,house_href) values (%s,%s,%s,%s)'
        cursor.execute(sql,(
            item['house_name'],item['house_price'],item['house_size'],item['house_href']
        ))
        # 提交数据库事务
        self.connect.commit()

        return item
           

8.2 启动Item Pipeline

在 settings.py 中进行设置:

ITEM_PIPELINES = {
    'scrapyselenium.pipelines.PymysqlPipeline':300
}
           

9. 运行

scrapy crawl xiaozhu 
           

10. 运行结果

Scrapy对接Selenium(说明在哪里进行对接为什么在这里):小猪短租网实战分析1. 新建项目2. 创建 Spider3. 网页的分析和自己爬取数据的确定4. 定义Item5. 构造 Request 请求列表6. 对接 Selenium (说明在哪里进行对接为什么在这里)7. 对页面进行解析8. 将数据存入数据库当中(Item Pipeline)9. 运行10. 运行结果
Scrapy对接Selenium(说明在哪里进行对接为什么在这里):小猪短租网实战分析1. 新建项目2. 创建 Spider3. 网页的分析和自己爬取数据的确定4. 定义Item5. 构造 Request 请求列表6. 对接 Selenium (说明在哪里进行对接为什么在这里)7. 对页面进行解析8. 将数据存入数据库当中(Item Pipeline)9. 运行10. 运行结果