Python Scrapy MongoDB爬蟲初學小項目(豆瓣電影排名Top250)

前言

本文項目基於Windows; Navicat 12 for MongoDB(很差用,也許使用NoSQL Manager for MongoDB會更好)。html


開發環境

so,本Scrapy項目,環境以下:python

操做系統:Win7mysql

開發語言及框架:Python3.7 Scrapy1.5.1web

開發工具:PyCharmsql

數據庫:MongoDB、MySQL數據庫

數據庫可視化工具:Navicat 12 for MongoDBjson

各類安裝、新建項目等請自行百度或查閱我前面的安裝文檔,這裏只作代碼記錄。瀏覽器

本項目所實現的主要功能:服務器

一、爬取豆瓣電影Top250的數據並存入本地MongoDB或MySQL中;架構

二、自定義Downloader middlewares,產生隨機的USER_AGENT


Scrapy架構圖

scrapy架構圖

組件(白話文解釋)

Scrapy Engine 引擎負責操做全部的數據流和事件,負責各個組件之間的通訊和數據交換。

Spiders 包含了request、接收response後的解析、提取item等功能。簡單來講數據的過濾、分析、再請求都在這個組件裏。

調度器(Scheduler) 本質就是個隊列。spider攜帶着request給引擎傳遞了請求以後,Scheduler負責給它們排個隊,後來的spider排到隊尾等着,隊頭的spider會被丟給引擎去執行。

下載器(Downloader) 引擎把接收到的request發給Downloader,Downloader獲取頁面數據再把獲得的一堆東東丟回給引擎。

Item Pipeline 負責處理被spider提取出來的item。典型的處理有過濾清理、 驗證及持久化(例如存取到數據庫中)。

下載器中間件(Downloader middlewares) 下載器中間件是在引擎及下載器之間的特定鉤子(specific hook),處理Downloader傳遞給引擎的response(也包括引擎傳遞給下載器的Request)。 其提供了一個簡便的機制,經過插入自定義代碼來擴展Scrapy功能。

一句話總結就是:處理下載請求部分,主要應用:封裝代理等隱藏咱們信息的地方。

Spider中間件(Spider middlewares) Spider中間件是在引擎及Spider之間的特定鉤子(specific hook),處理spider的輸入(response)和輸出(items及requests)。 其提供了一個簡便的機制,經過插入自定義代碼來擴展Scrapy功能。


項目目錄

項目目錄

代碼筆記

一、scrapy.cfg

[settings]
default = Scrapy_DoubanMoviesTop250.settings

[deploy]
project = Scrapy_DoubanMoviesTop250

settings: 項目配置文件

deploy: 項目別名


二、settings.py(節選)

# -*- coding: utf-8 -*-

# 設置導出編碼格式爲utf-8
FEED_EXPORT_ENCODING = 'utf-8'

BOT_NAME = 'Scrapy_DoubanMoviesTop250'

SPIDER_MODULES = ['Scrapy_DoubanMoviesTop250.spiders']
NEWSPIDER_MODULE = 'Scrapy_DoubanMoviesTop250.spiders'


# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.5
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16

# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
    'Scrapy_DoubanMoviesTop250.middlewares.my_useragent': 543
}

# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'Scrapy_DoubanMoviesTop250.pipelines.ScrapyDoubanmoviestop250Pipeline': 300,
}

# MongoDB設置
mongo_host = '127.0.0.1'
mongo_port = 27017
mongo_db_name = 'douban'
mongo_db_collection = 'douban_movie'

# mysql設置
mysql_host = '127.0.0.1'
mysql_port = 3306
mysql_user = 'root'
mysql_password = '123456'
mysql_db_name = 'scrapy_douban'

如下是對上述代碼的拆分解釋:

(1)導出格式編碼聲明:

# 設置導出編碼格式爲utf-8
FEED_EXPORT_ENCODING = 'utf-8'

(2)USER_AGENT改成本身瀏覽器的值,F12直接看就好

USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'

PS:爲何修改USER_AGENT?

大多數狀況下,網站都會根據咱們的請求頭信息來區分你是否是一個爬蟲程序,若是一旦識別出這是一個爬蟲程序,很容易就會拒絕咱們的請求,所以咱們須要給咱們的爬蟲手動添加請求頭信息,來模擬瀏覽器的行爲。


(3)設置不遵照robots.txt規則

ROBOTSTXT_OBEY = False

PS:robots.txt規則是個什麼東東?

robots.txt 是遵循 Robot協議 的一個文件,它保存在網站的服務器中,它的做用是,告訴搜索引擎爬蟲,本網站哪些目錄下的網頁 不但願 你進行爬取收錄。在Scrapy啓動後,會在第一時間訪問網站的 robots.txt 文件,而後決定該網站的爬取範圍。

固然,咱們並非在作搜索引擎,某些狀況下咱們想要獲取的內容偏偏是被 robots.txt 禁止訪問的,這個時候,咱們就要將此配置項設置爲 False ,拒絕遵照 Robot協議。


(4)下載延遲設置爲0.5

DOWNLOAD_DELAY = 0.5

對單個IP進行併發請求的最大值,默認是0,單位是秒。注意:設置太大,大規模抓取等待時間過長,設置過小,短期增大服務器負載,會被咔嚓。

(5)自定義Downloader middlewares,產生隨機USER_AGENT

DOWNLOADER_MIDDLEWARES = {
    # 這裏的My_useragent就是你自定義的中間件名稱,543表示執行順序,越大的越日後執行,默認從543開始
    'Scrapy_DoubanMoviesTop250.middlewares.my_useragent': 543
}

白話文解釋:網站是根據請求頭信息來區分爬蟲程序的,當咱們大量爬取同一個網站的數據,一直使用同一個請求頭可能會被抓包而後咔嚓掉,因此能夠搞一個隨機生成USER_AGENT的中間件更好地隱藏本身。

(6)開啓ITEM_PIPELINES,默認便可

ITEM_PIPELINES = {
   'Scrapy_DoubanMoviesTop250.pipelines.ScrapyDoubanmoviestop250Pipeline': 300,
}

要持久化數據你不開試試?

(7)MongoDB設置

# MongoDB設置
mongo_host = '127.0.0.1'
mongo_port = 27017
mongo_db_name = 'douban'
mongo_db_collection = 'douban_movie'

(8)MySQL設置

# mysql設置
mysql_host = '127.0.0.1'
mysql_port = 3306
mysql_user = 'root'
mysql_password = '123456'
mysql_db_name = 'scrapy_douban'

三、items.py

寫spider以前,你得先弄清楚你須要哪些數據?items.py就是你聲明本身所需的數據名字的地方。

import scrapy

class ScrapyDoubanmoviestop250Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 排名
    serial_number = scrapy.Field()
    # 電影名稱
    movie_name = scrapy.Field()
    # 介紹
    introduction = scrapy.Field()
    # 評分
    score = scrapy.Field()
    # 評論數
    evaluation = scrapy.Field()
    # 電影描述
    description = scrapy.Field()

四、douban_spider.py

# -*- coding: utf-8 -*-
import scrapy
from Scrapy_DoubanMoviesTop250.items import ScrapyDoubanmoviestop250Item

class DoubanSpiderSpider(scrapy.Spider):
    # 爬蟲名字 和項目名不可重複
    name = 'douban_spider'
    # 容許的域名
    allowed_domains = ['movie.douban.com']
    # 入口url,扔到調度器Scheduler裏面去
    start_urls = ['http://movie.douban.com/top250']

    # spider默認解析方法。
    # 該方法負責解析返回的數據(response data),提取數據(生成item)以及生成須要進一步處理的URL的 Request 對象。
    def parse(self, response):
        # 獲取電影條目
        movie_list = response.xpath("//div[@class='article']/ol[@class='grid_view']/li")
        for movie_item in movie_list:
            item = ScrapyDoubanmoviestop250Item()
            # 寫詳細的xpath,進行數據解析
            item['serial_number'] = movie_item.xpath(".//div[@class='item']//em/text()").extract_first()
            item['movie_name'] = movie_item.xpath(".//div[@class='info']//div[@class='hd']//a//span[1]/text()").extract_first()
            # 頁面多行數據的處理
            introduction_list = movie_item.xpath(".//div[@class='info']//div[@class='bd']//p[1]/text()").extract()
            for introduction in introduction_list:
                item['introduction'] = "".join(introduction.split())
            item['score'] = movie_item.xpath(".//span[@class='rating_num']/text()").extract_first()
            item['evaluation'] = movie_item.xpath(".//div[@class='star']//span[4]/text()").extract_first()
            item['description'] = movie_item.xpath(".//p[@class='quote']//span/text()").extract_first()
            # 將數據yield到pipline裏去,進行數據清洗、存儲等操做
            yield item

        # 解析下一頁,獲取下一頁的xpath
        next_link = response.xpath("//span[@class='next']//link/@href").extract()
        if next_link:
            next_link = next_link[0]
            yield scrapy.Request("http://movie.douban.com/top250"+next_link, callback=self.parse)

嗯。。。學完了純python的爬取以後,學習這個代碼壓力應該不大。看到這個下一頁的聲明,也可以理解調度器Scheduler的做用了。


五、數據持久化操做

寫完douban_spider.py以後,其實就能夠拿到數據了,你能夠選擇導出數據文件,也能夠將數據存入數據庫中。

注意:可在settings.py中配置導出文件編碼方式爲utf-8,儘可能避免亂碼問題。

一、保存數據爲.json或.csv文件

進入項目中的spiders文件夾中,輸入命令:

scrapy crawl 你在spider文件中定義的爬蟲名字 -o 文件名稱.json

例:scrapy crawl douban_spider -o movies.json,在當前文件夾中導出。

二、保存至MongoDB中

打開pipelines.py,初始化數據庫鏈接並插入數據,代碼以下:

# -*- coding: utf-8 -*-
import pymongo
from Scrapy_DoubanMoviesTop250.settings import mongo_host, mongo_port, mongo_db_name, mongo_db_collection

class ScrapyDoubanmoviestop250Pipeline(object):
    def __init__(self):
        # 獲取數據庫配置信息
        host = mongo_host
        port = mongo_port
        db_name = mongo_db_name
        db_collection = mongo_db_collection

        # 獲取數據庫鏈接
        get_connection = pymongo.MongoClient(host=host, port=port)
        # 在鏈接中拿到數據庫信息
        local_db = get_connection[db_name]
        # 獲得集合信息
        self.post = local_db[db_collection]

    def process_item(self, item, spider):
        data = dict(item)
        self.post.insert(data)
        return item

二、保存至MySQL中

打開pipelines.py,初始化數據庫鏈接並插入數據,代碼以下:

# -*- coding: utf-8 -*-
import pymysql
from Scrapy_DoubanMoviesTop250.settings import mysql_host, mysql_port, mysql_user, mysql_password, mysql_db_name

class ScrapyDoubanmoviestop250Pipeline(object):
    # 鏈接數據庫:
        self.connect = pymysql.connect(
            host=mysql_host,
            port=mysql_port,
            user=mysql_user,
            password=mysql_password,
            database=mysql_db_name,
            charset='utf8',
            use_unicode=True
        )

        # 經過cursor進行增刪改查
        self.cursor = self.connect.cursor()

    def process_item(self, item, spider):
        insert_sql = """insert into douban_movie(serial_number, movie_name, introduction, score, evaluation, description) values (%s, %s, %s, %s, %s, %s)"""
        self.cursor.execute(insert_sql, (item['serial_number'], item['movie_name'], item['introduction'], item['score'], item['evaluation'], item['description']))
        self.connect.commit()
        return item

    def close_spider(self, spider):
        self.cursor.close()
        self.connect.close()

這裏再次聲明一下:settings.py中必須開啓ITEM_PIPELINES,不然scrapy可不會智能地幫你開啓鏈接數據庫的管道的喔!詳見文中 代碼筆記——二、settings.py(節選)—— (6)開啓ITEM_PIPELINES,默認便可。

到此,基本上這個項目的目的也就完成了:使用Scrapy框架抓取數據並存儲到MongoDB或MySQL中。


六、隨機User_Agent中間件示例

用途:詳見文中 代碼筆記——二、settings.py(節選)—— (2)USER_AGENT改成本身瀏覽器的值,F12直接看就好、(5)自定義Downloader middlewares,產生隨機USER_AGENT。

打開middlewares.py,在已有代碼後追加一個新的類My_useragent:

class My_useragent(object):
    def process_request(self, request, spider):
        USER_AGENT_LIST = [
            'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
            'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
            'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
            'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
            'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
            'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
            'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
            'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'
        ]
        request.headers['User_Agent'] = random.choice(USER_AGENT_LIST)

這個函數process_request(self, request, spider)並非本身寫的,是下載器中間件Downloader middlewares自帶的方法,每個request對象都會通過該方法。固然還有process_response(self, request, response, spider),當下載器完成請求後,返回response給引擎的時候調用。

這裏的USER_AGENT_LIST能夠本身去網上百度一個,看心情寫。

最後,別忘了去settings.py中配置一下DOWNLOADER_MIDDLEWARES。

貼上個人配置:

DOWNLOADER_MIDDLEWARES = {
    # 這裏的My_useragent就是你自定義的中間件名稱,543表示執行順序,越大的越日後執行,默認從543開始
    'Scrapy_DoubanMoviesTop250.middlewares.My_useragent': 543
}

七、模擬main方法

若是你不滿於每次執行.py文件都須要輸入命令,也能夠在項目中這麼作:

在項目根目錄下新建main.py,輸入如下代碼,不須要手動配置,直接右鍵Run 'main'便可,PyCharm會幫你配置好的。

from scrapy import cmdline
cmdline.execute('scrapy crawl douban_spider'.split())

嗯,抄代碼是很簡單的,真正地去理解把它融入爲本身的還須要一段時間。本篇筆記是學習以後的整理,其實很是像流水帳,我中間遇到的問題也沒有記錄,Navicat的使用也沒有記錄,我的很是不喜歡但也不想再重作了。年前Python的學習時間還很充裕,以後會邊學邊寫筆記的,一整套流程按發展的步驟詳細地記錄下來。Over~

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息