Scrapy對接Selenium(說明在哪裏進行對接爲什麼在這裏):小豬短租網實戰分析

在沒有系統學習框架進行爬蟲的時候,已經可以使用selenium對動態渲染的網頁和Ajax加載數據的網頁進行爬取,但代碼的整體邏輯在於自己對於方法的認識編寫和使用,沒有很強的邏輯框架性,在自學Scrapy框架的時候也學到對於Selenium的對接,最近進行了學習,現在和大家分享,有什麼不足或錯誤的地方請評論或私信喲😁

使用selenium對網頁抓取的原理在於,使用selenium模擬登陸瀏覽器進行抓取,不需要關心頁面後臺發生的請求,也不需要分析頁面渲染過程,只需要關注頁面最終結果即可,在進行網頁跳轉的時候,也只需要關心URL的變化規律,從而來構造請求列表來重複進行請求,也不需要關心如何去構造請求頭。

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,所以就直接偷懶選擇了固定地點後的頁面去進行分析。
在這裏插入圖片描述
在這裏插入圖片描述
由於是使用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去查看源代碼,這個是輔助查詢,主要代碼依據是在服務器返回的請求響應中去查看源代碼,源代碼很可能在第一個響應中:
在這裏插入圖片描述
並發現每一個房子的相關信息都存在 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. 運行結果

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章