【實戰】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),歡迎加入!