Scrapy+selenium完成動態網站爬蟲框架封裝 | Python 主題月

本文正在參加「Python主題月」,詳情查看 活動連接css

前言

scrapy是一個很是成熟的爬蟲框架,裏面幾乎封裝好了開發者所須要的全部模塊,例如:request,代理,日誌,url自動去重等等,一些不太滿意的模塊也是稍加修改就行。但scrapy只能爬靜態網頁,若是須要爬動態渲染的網頁的話還須要藉助第三方組件,例如selenium或者splash.html

爲何選擇selenium

selenium和splash都是很是優秀的動態網頁渲染工具。但selenium與splash相比,主要有如下幾個有點:mysql

  1. selenium能夠直接在瀏覽器運行,就像真是的用戶操做同樣。
  2. selenium的文檔更加詳細,國內的教程也多,splash教程真是少的可憐。
  3. selenium支持的模擬用戶行爲的操做命令更加全面詳細,splash的部分用戶操做行爲也有,但具體怎麼使用,經過他們的手冊我是沒看懂。

綜上幾點仍是選擇selenium好一點,但並非splash全無優勢,我以前寫過PHP的爬蟲,用的就是splash,我的意見:若是沒有特別複雜的交互,用splash仍是能夠的,splash提供的api,咱們只須要把請求頭,代理和url傳給splash,也能獲得渲染好的html.git

本文要實現的功能

  1. Scrapy的安裝
  2. 配置selenium
  3. sqlalchemy完成數據入庫

Scrapy的安裝

安裝scrapy

在終端輸入 pip install scrapyweb

建立scrapy項目

  1. 建立項目,命令:scrapy startproject 項目名稱
  2. 建立爬蟲文件,命令:scrapy genspider 文件名稱 域名

我執行的sql

scrapy startproject spider
複製代碼
scrapy genspider douban douban.com
複製代碼

生成的項目目錄就是這樣的chrome

spider
    spider
        spiders
            __init__.py
            douban.py
        __init__.py
        items.py
        middlewares.py
        piplines.py
        settings.py
    scrapy.cfg
複製代碼

添加相關目錄

spider
    spider
        common  # 公共配置文件目錄 
            __init__.py
            conf.py # 數據庫配置信息
        models # mysql model類
            __init__.py  
        spiders
            __init__.py
            douban.py
        __init__.py
        items.py
        middlewares.py
        piplines.py
        settings.py
    scrapy.cfg
複製代碼

配置selenium

瀏覽器驅動的安裝就不說了,由於每一個系統安裝方式都不同,網上各個系統的安裝方法都很詳細,也不是很難。數據庫

引入selenium包

pip安裝selenium包api

pip install selenium
複製代碼

更改代碼

spider/spiders/douban.py瀏覽器

import scrapy

from selenium import webdriver
# 使用無頭瀏覽器
from selenium.webdriver.chrome.options import Options  
# 無頭瀏覽器設置
chorme_options = Options()
chorme_options.add_argument("--headless")
chorme_options.add_argument("--disable-gpu")

class DoubanSpider(scrapy.Spider):
    name = 'douban'
    allowed_domains = ['douban.com']
    start_urls = ['https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0']

    # 實例化一個瀏覽器對象
    def __init__(self):
        self.browser = webdriver.Chrome(options=chorme_options)
        super().__init__()

    def parse(self, response):
        print(response.body)
        pass

    def close(self, spider):
        print('爬蟲結束,關閉瀏覽器')
        self.browser.quit()
複製代碼

settings.py配置文件裏更改一些配置

# 更改用戶代理(也能夠設置成動態切換,我的感受不必)
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
# 關閉聽從robots協議
ROBOTSTXT_OBEY = False
# 打開下載中間件
DOWNLOADER_MIDDLEWARES = {
   'spider.middlewares.SpiderDownloaderMiddleware': 543,
}
# 數據處理管道
ITEM_PIPELINES = {
   'spider.pipelines.SpiderPipeline': 300,
}
複製代碼

middlewares.py中間件文件修改:
SpiderDownloaderMiddleware類的process_response方法修改,用瀏覽器驅動加載url

def process_response(self, request, response, spider):
    """
    三個參數:
    # request: 響應對象所對應的請求對象
    # response: 攔截到的響應對象
    # spider: 爬蟲文件中對應的爬蟲類的實例對象, 能夠經過這個參數拿到中的一些屬性或方法
    """
    spider.browser.get(url=request.url)
    # 等待加載,  能夠用顯示等待來優化.
    time.sleep(1)  
    row_response = spider.browser.page_source
    # 參數url指當前瀏覽器訪問的url(經過current_url方法獲取), 在這裏參數url也能夠用request.url
    return HtmlResponse(url=spider.browser.current_url, body=row_response, encoding="utf8",
                        request=request)  
複製代碼

至此,selenium的配置就完了

引入sqlalchemy完成數據入庫

在Python中,最有名的ORM框架是SQLAlchemy,文檔齊全使用方便,同時爲高效和高性能的數據庫訪問設計,實現了完整的企業級持久模型。

添加數據庫鏈接配置文件

數據庫配置文件spider/common/conf.py

class conf:
    mysql = {
        # 數據庫本地環境配置信息
        'dev': {
            'host': '127.0.0.1',
            'database': 'test',
            'user': 'user',
            'password': 'passord',
            'port': 3306,
        },
        # 測試服務器配置信息
        'test': {
            'host': '127.0.0.1',
            'database': 'test',
            'user': 'user',
            'password': 'passord',
            'port': 3306,
        },
        # 線上服務器配置信息
        'prod': {
            'host': '127.0.0.1',
            'database': 'test',
            'user': 'user',
            'password': 'passord',
            'port': 3306,
        },
    }
}
複製代碼

運行環境配置文件 spider/common/env.py

# coding:utf-8
"""
環境標識(不可隨意更改,此文件不上傳到git)
    本地環境 dev
    測試環境 test
    線上環境 prod
"""

class env:
    env = 'dev'
複製代碼

添加數據庫鏈接

spider/models/__init__.py文件裏添加數據庫鏈接

# -*- coding: utf-8 -*-
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from spider.common.conf import conf
from spider.common.env import env

Base = declarative_base()
env = env.env
mysql = conf.mysql[env]
engine = create_engine(
    url="mysql+pymysql://{user}:{password}@{host}/{database}".format(
        user=mysql['user'],
        password=mysql['password'],
        host=mysql['host'],
        database=mysql['database']),
    encoding='UTF-8',
    pool_size=5,  # 鏈接池大小
    max_overflow=10,  # 超過鏈接池大小外最多建立的鏈接
    pool_timeout=30,  # 池中沒有線程最多等待的時間,不然報錯
    pool_pre_ping=True
)
Session = sessionmaker(bind=engine)()
複製代碼

創建數據表模型

spider/models目錄下添加Movie.py文件

from sqlalchemy import Column, String, Integer, DateTime
from spider.models import Base


class Movie(Base):
    # 表公共信息配置
    __tablename__ = "movie"

    # 表字段定義
    id = Column(Integer, primary_key=True)
    title = Column(String(100), comment='影片名')
    created_at = Column(DateTime, comment='添加時間')
    updated_at = Column(DateTime, comment='更新時間')
複製代碼

添加item字段

items.py添加MovieItem

import scrapy

class SpiderItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass

class MovieItem(scrapy.Item):
    title = scrapy.Field()
    pass
複製代碼

更改爬蟲程序

spider/spiders/douban.py添加數據解析

import scrapy

from selenium import webdriver
# 使用無頭瀏覽器
from selenium.webdriver.chrome.options import Options
# 無頭瀏覽器設置
from spider.items import MovieItem

chorme_options = Options()
chorme_options.add_argument("--headless")
chorme_options.add_argument("--disable-gpu")

class DoubanSpider(scrapy.Spider):
    name = 'douban'
    allowed_domains = ['douban.com']
    start_urls = ['https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0']

    # 實例化一個瀏覽器對象
    def __init__(self):
        self.browser = webdriver.Chrome(options=chorme_options)
        super().__init__()

    def parse(self, response):
        for value in response.css('.list-wp>.list>a'):
            item = MovieItem()
            item['title'] = value.css('.cover-wp>img::attr(alt)').extract_first()
            yield item
        pass

    def close(self, spider):
        print('爬蟲結束,關閉瀏覽器')
        self.browser.quit()
複製代碼

管道入庫

pipelines.py將數據添加到數據庫

import datetime

from spider.models import Session
from spider.models.Movie import Movie


class SpiderPipeline:

    """
    爬蟲被打開的時候執行
    :param spider:
    :return:
    """
    def open_spider(self, spider):
        print("爬蟲開始....")

    """
    爬蟲有item傳過來的時候會被調用
    :param item:
    :param spider:
    :return:
    """
    def process_item(self, item, spider):
        try:
            data = Movie(title=item['title'], created_at=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                         updated_at=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            Session.add(data)
            Session.commit()
        except():
            Session.rollback()
            return None

    """
    爬蟲關閉的時候被調用
    :param spider:
    :return:
    """
    def close_spider(self, spider):
        # 關閉數據庫鏈接
        Session.close()
        print("爬蟲結束,關閉數據庫鏈接")
複製代碼

總結

至此一個簡單的爬蟲程序就完成了,上面全部的請求都是走selenium組件的,有些靜態網頁是不須要的,在中間件裏判斷一下就好了。本篇只是簡單的封裝,完善的爬蟲程序還須要設置代理,考慮分佈式,增量爬蟲,這裏就不深刻介紹了。

相關文章
相關標籤/搜索