本文項目基於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 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功能。
[settings] default = Scrapy_DoubanMoviesTop250.settings [deploy] project = Scrapy_DoubanMoviesTop250
settings: 項目配置文件
deploy: 項目別名
# -*- 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'
如下是對上述代碼的拆分解釋:
# 設置導出編碼格式爲utf-8 FEED_EXPORT_ENCODING = 'utf-8'
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?
大多數狀況下,網站都會根據咱們的請求頭信息來區分你是否是一個爬蟲程序,若是一旦識別出這是一個爬蟲程序,很容易就會拒絕咱們的請求,所以咱們須要給咱們的爬蟲手動添加請求頭信息,來模擬瀏覽器的行爲。
ROBOTSTXT_OBEY = False
PS:robots.txt規則是個什麼東東?
robots.txt 是遵循 Robot協議 的一個文件,它保存在網站的服務器中,它的做用是,告訴搜索引擎爬蟲,本網站哪些目錄下的網頁 不但願 你進行爬取收錄。在Scrapy啓動後,會在第一時間訪問網站的 robots.txt 文件,而後決定該網站的爬取範圍。
固然,咱們並非在作搜索引擎,某些狀況下咱們想要獲取的內容偏偏是被 robots.txt 禁止訪問的,這個時候,咱們就要將此配置項設置爲 False ,拒絕遵照 Robot協議。
DOWNLOAD_DELAY = 0.5
對單個IP進行併發請求的最大值,默認是0,單位是秒。注意:設置太大,大規模抓取等待時間過長,設置過小,短期增大服務器負載,會被咔嚓。
DOWNLOADER_MIDDLEWARES = { # 這裏的My_useragent就是你自定義的中間件名稱,543表示執行順序,越大的越日後執行,默認從543開始 'Scrapy_DoubanMoviesTop250.middlewares.my_useragent': 543 }
白話文解釋:網站是根據請求頭信息來區分爬蟲程序的,當咱們大量爬取同一個網站的數據,一直使用同一個請求頭可能會被抓包而後咔嚓掉,因此能夠搞一個隨機生成USER_AGENT的中間件更好地隱藏本身。
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'
寫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()
# -*- 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,儘可能避免亂碼問題。
進入項目中的spiders文件夾中,輸入命令:
scrapy crawl 你在spider文件中定義的爬蟲名字 -o 文件名稱.json
例:scrapy crawl douban_spider -o movies.json,在當前文件夾中導出。
打開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
打開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中。
用途:詳見文中 代碼筆記——二、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 }
若是你不滿於每次執行.py文件都須要輸入命令,也能夠在項目中這麼作:
在項目根目錄下新建main.py,輸入如下代碼,不須要手動配置,直接右鍵Run 'main'便可,PyCharm會幫你配置好的。
from scrapy import cmdline cmdline.execute('scrapy crawl douban_spider'.split())
嗯,抄代碼是很簡單的,真正地去理解把它融入爲本身的還須要一段時間。本篇筆記是學習以後的整理,其實很是像流水帳,我中間遇到的問題也沒有記錄,Navicat的使用也沒有記錄,我的很是不喜歡但也不想再重作了。年前Python的學習時間還很充裕,以後會邊學邊寫筆記的,一整套流程按發展的步驟詳細地記錄下來。Over~