1. 程式人生 > >【實戰】scrapy-redis + webdriver 爬取航空網站

【實戰】scrapy-redis + webdriver 爬取航空網站

引言

今天給大家帶來的是scrapy-redis + webdriver實戰案例。在爬蟲編寫過程中,我們經常會遇到以下的情況,想要用scrapy框架,但是因為網站的原因,還想要用webdriver,那麼要如何實現scrapy + webdriver呢?其實很簡單,大家都知道,在scrapy中,我們可以在中介軟體中擴充套件自己想要的功能,所以webdriver也是可以新增在中介軟體中的。

 

需求分析

爬取東航網站中航班資訊(http://www.ceair.com/)。分析網站後可以發現,在查詢航班資訊的時候,網站做了介面的呼叫,我們可以採用分析介面的方式,分析介面,然後偽造介面資料爬取結果,但這和我們這次的主題不一致,暫時先放棄。我們這次採用webdriver的方式爬取航班資訊。

 

下載中介軟體的編寫

其實整個專案主要是在編寫下載中介軟體。下面是下載中介軟體的內容。

class SeleniumMiddleware():
    # Middleware中會傳遞進來一個spider,這就是我們的spider物件,從中可以獲取__init__時的chrome相關元素
    def process_request(self, request, spider):
        '''
        用chrome抓取頁面
        :param request: Request請求物件
        :param spider: Spider物件
        :return: HtmlResponse響應
        '''
        print(f"chrome is getting page")

        # 初始化ChromeOption
        option = webdriver.ChromeOptions()
        option.add_argument('headless') # 無頭模式
        # 新增UA
        option.add_argument(
            '--user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"')
        option.add_argument('--disable-infobars') # 禁用webdriver控制瀏覽器的提示

        # 建立driver例項
        driver = webdriver.Chrome(chrome_options=option)

        # 訪問目標網址
        driver.get(request.url)

        # 等待載入完成,這裡應該寫成動態載入,由於是演示,就偷懶了
        time.sleep(5)

        body = driver.page_source

        # 關閉driver
        driver.quit()

        # 通過page_source構建新的response病返回
        return HtmlResponse(url=request.url,
                            body=body,
                            request=request,
                            # 最好根據網頁的具體編碼而定
                            encoding='utf-8',
                            status=200)

 

在下載中介軟體中,我們使用webdriver訪問url地址,並將page_source構建成為新的response返回給spider。

 

其他部分

 

完成了中介軟體的編寫之後,我們還需要完善一下其他部分。首先是要在settings檔案中開啟下載中介軟體,如果不開啟中介軟體的話,雖然我們編寫了下載中介軟體,但是卻不會呼叫。

DOWNLOADER_MIDDLEWARES = {
    # 'example.middlewares.UserAgentMiddleware':543,
    'example.middlewares.SeleniumMiddleware':543,
}

 

在setting檔案中設定好中介軟體後,我們需要完善一下spider檔案。這裡將分析省略,直接上程式碼。

from scrapy_redis.spiders import RedisSpider
from bs4 import BeautifulSoup
from example.items import ExampleItem
import time


class MySpider(RedisSpider):
    """Spider that reads urls from redis queue (myspider:start_urls)."""
    name = 'ceair'
    redis_key = 'ceair'

    def __init__(self, *args, **kwargs):
        # Dynamically define the allowed domains list.
        domain = kwargs.pop('domain', '')
        self.allowed_domains = filter(None, domain.split(','))
        super(MySpider, self).__init__(*args, **kwargs)

    def parse(self, response):

        html_body = BeautifulSoup(response.text,'lxml')
        flights = html_body.find_all(class_='flight')
        for flight_info in flights:
            item = ExampleItem()
            title = flight_info.find(class_='title')
            item['title'] = (title.get_text())

            start_info = flight_info.find(class_='airport r')
            item['start_info'] = (start_info.get_text())

            middle_info = flight_info.find(class_='mid')
            item['middle_info'] = (middle_info.get_text())

            end_info = flight_info.find(class_='airport')
            item['end_info'] = (end_info.get_text())

            cost_time = flight_info.find('dfn')
            item['cost_time'] = (cost_time.get_text())

            price_luxury = flight_info.find(class_='luxury')
            item['price_luxury'] = (price_luxury.get_text())

            price_economy = flight_info.find(class_='economy')
            item['price_economy'] = (price_economy.get_text())

            price_member = flight_info.find(class_='member')
            item['price_member'] = (price_member.get_text())

            item['update_time'] = time.strftime('%Y.%m.%d %H:%M:%S',time.localtime(time.time()))

            yield item

 

管道檔案。同樣省略講解。

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/topics/item-pipeline.html
from datetime import datetime
import pymongo

class ExamplePipeline(object):
    def process_item(self, item, spider):
        curr = pymongo.MongoClient()
        db = curr['ceair']
        collection = db['ceair']
        collection.insert_one(item)
        curr.close()
        print(item)

 

最後,為了方便執行爬蟲,我們可以建立一個main檔案,這樣就不用每次都在命令列中敲命令了。下面是main檔案內容。

from scrapy import cmdline
cmdline.execute("scrapy crawl ceair".split())

總結

這裡我們只是寫了分散式爬蟲的從端檔案,從端檔案只負責爬取並存儲內容,我們還需要編寫主端檔案,需要分析並構建url,並將url儲存在redis資料庫中。這裡就不做詳細介紹了。

原始碼:

連結:https://pan.baidu.com/s/1LAR3K0UhefPi-8s1TxUCZA  密碼:jvx8

 

Python軟體開發測試交友群QQ:952490269(加群備註software),歡迎加入!