學了python之后一直在給自己找點兒什么需求練練手,爬蟲是學python最快的途徑,就想著爬點豆瓣電影的數據吧,在經過了一系列重復造輪子之后,決定體驗一下scrapy。
scrapy的架構圖:
1、引擎(ScrapyEngine): 用來處理整個系統的通訊,數據流處理, 觸發事務(框架核心)。
2、調度器(Scheduler): 用來接受引擎發過來的請求, 壓入隊列中, 并在引擎再次請求的時候返回. 可以想像成一個URL(抓取網頁的網址或者說是鏈接)的優先隊列, 由它來決定下一個要抓取的網址是什么, 同時去除重復的網址。
3、下載器(Downloader): 用于下載網頁內容, 并將網頁內容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的異步模型上的)。
4、爬蟲(Spiders): 爬蟲是主要干活的, 用于從特定的網頁中提取自己需要的信息, 即所謂的實體(Item)。用戶也可以從中提取出鏈接,讓Scrapy繼續抓取下一個頁面。
5、項目管道(Pipeline): 負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的信息。當頁面被爬蟲解析后,將被發送到項目管道,并經過幾個特定的次序處理數據。
6、下載器中間件(Downloader Middlewares): 位于Scrapy引擎和下載器之間的框架,主要是處理Scrapy引擎與下載器之間的請求及響應。
7、爬蟲中間件(Spider Middlewares): 介于Scrapy引擎和爬蟲之間的框架,主要工作是處理蜘蛛的響應輸入和請求輸出。
8、調度中間件(Scheduler Middewares): 介于Scrapy引擎和調度之間的中間件,從Scrapy引擎發送到調度的請求和響應
scrapy流程:
1.Spider將初始url告訴Engine,Engine將url添加到調度器的請求隊列中
2.Engine從調度器隊列中拿到下一個要請求的url,交給下載器(下載器中間件可以設置代理之類。。),下載器下載網頁內容,交還給引擎
3.Engine將從下載器拿到的網頁內容,交給spider,spider爬取所需要的內容,生成item交還給Engine,如果需要繼續爬取,將新的url告訴Engine,并添加到調度器的請求隊列中
4.pipeline 從Engine拿到爬取的實體進行處理
python&scrapy安裝:
開始
創建項目:
scrapy startproject 項目名稱
目錄介紹:
.cfg 項目配置文件 定義了項目配置文件路徑,部署信息等內容
items.py 定義item數據結構的地方
settings.py 項目的設置文件,定義項目的全局設置
生成spiders文件:
在spiders目錄中進入命令行輸入 scrapy genspider 爬蟲名 要爬取的域名
刷新項目文件目錄
spider文件中:
name : 爬蟲的名稱
start_urls : 為初始爬蟲目錄,就是第一次爬取的地址url
執行爬蟲文件 :
scrapy crawl 爬蟲名稱
爬取豆瓣電影網站內容
在項目磁盤目錄下打開命令行輸入
scrapy startproject douban_demo
生成項目文件
修改settings.py文件中USER_AGENT和ROBOTSTXT_OBEY:不然請求會被攔截
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
ROBOTSTXT_OBEY = False
在spiders目錄中進入命令行輸入
scrapy genspider douban_spider movie.douban.com
之后會在spiders目錄中生成一個douban_spider.py 的文件,修改start_urls:
start_urls = ['http://movie.douban.com/top250']
打開頁面,我們接下來要抓取這些數據
在items.py中創建我們的數據模型:
class DouBanItem(scrapy.Item):
#電影編號
movie_num = scrapy.Field()
#電影封面地址
movie_imgurl = scrapy.Field()
#電影名稱
movie_name = scrapy.Field()
#電影參與人員
movie_person = scrapy.Field()
#電影評分
movie_grade = scrapy.Field()
#電影口號
movie_slogen = scrapy.Field()
douban_spider.py中 的 parse方法,就是我們寫爬蟲代碼的地方
檢查頁面,查看頁面標簽詳情,可以看到頁面的標簽結構
爬取數據:
movies = response.css('div.item')
for movie in movies:
movie_num = movie.css('em::text').extract_first()
movie_imgurl = movie.css('img::attr(src)').extract_first()
movie_name = movie.css('.title::text').extract_first()
movie_person = movie.css('.bd p::text').extract_first()
movie_grade = movie.css('.rating_num::text').extract_first()
movie_slogen = movie.css('.inq::text').extract_first()
doubanItem = DouBanItem()
doubanItem['movie_num'] = movie_num
doubanItem['movie_imgurl'] = movie_imgurl
doubanItem['movie_name'] = movie_name
doubanItem['movie_person'] = movie_person
doubanItem['movie_grade'] = movie_grade
doubanItem['movie_slogen'] = movie_slogen
將爬取到的數據加入pipline管道
yield doubanItem
將數據寫入txt文本文件
with open('movie_info.txt','a+',encoding='utf-8') as f:
f.write(movie_num+" : "+movie_name+" : \t"+movie_grade+"\n")
f.write('封面圖片地址 : '+movie_imgurl+'\n')
f.write('參與人員 : '+movie_person+'\n')
f.write(movie_slogen+"\n")
f.write('\n-----------------------------------------\n')
使用a+追加方式,編碼使用utf-8,打開文本文件,往里寫入
繼續爬取下一頁數據:
next_page = response.css('span.next a::attr(href)').extract_first()
if next_page is not None:
realUrl = "http://movie.douban.com/top250"+next_page
realUrl = response.urljoin(realUrl)
yield scrapy.Request(realUrl,callback=self.parse)
根據css找到下一頁按鈕中的地址,這個頁面是需要拼接host地址,如果 is not None 表示還有下一頁,
urljoin(url)將地址添加到調度器請求隊列中,scrapy.Request(realUrl,callback=self.parse)之情請求,設置回調使用當前parse方法作為返回數據的處理方法
用爬取到的數據,生成json文件
在命令行中(可以使用pycharm中的Terminal命令行)執行爬蟲文件
scrapy crawl douban_spider -o douban.json
'douban_spider'是douban_spider.py中name字段的值
執行完本地就會生成一個json文件
用爬取到的數據,生成csv格式文件
在命令行中(可以使用pycharm中的Terminal命令行)執行爬蟲文件
scrapy crawl douban_spider -o douban.csv
'douban_spider'是douban_spider.py中name字段的值
執行完本地就會生成一個csv文件
爬取數據存儲MongoDB
首先在settings.py文件中打開 pipeline開關,并在最后面配置mongodb
ITEM_PIPELINES = {
'scrapy_demo.pipelines.ScrapyDemoPipeline': 300,
}
mongo_host = '127.0.0.1'
mongo_port = 27017
mongo_db_name = 'douban'
mongo_db_collection = 'douban_movie
在pipelines.py中編寫代碼
首先導入settings中的mongodb配置和mongodb
import pymongo
from scrapy_demo.settings import mongo_db_collection,mongo_db_name,mongo_host,mongo_port
在構造函數中傳入配置參數:
def __init__(self):
# 端口號
port = mongo_port
# 基地址
host = mongo_host
# 數據庫名
dbname = mongo_db_name
# 表名
sheetname = mongo_db_collection
# 創建client
client = pymongo.MongoClient(host=host,port=port)
# 指定數據庫
mydb = client[dbname]
# 找到表
self.post = mydb[sheetname]
在process_item方法中進行數據插入的編寫
def process_item(self, item, spider):
# 將模型轉化為字典
data = dict(item)
# 將字典數據插入mongodb
self.post.insert(data)
return item
運行之后就可以在數據庫中看到咱們已經添加了數據
對爬蟲進行偽裝
設置代理ip
為了不讓要爬取的網站發現我們的爬取動作,需要對爬蟲進行一些偽裝,
我們可以通過下載器中間件(Downloader Middlewares)對我們的請求進行偽裝
將settings.py中的DOWNLOADER_MIDDLEWARES配置打開(543為優先級,數字越小,優先級越高)
DOWNLOADER_MIDDLEWARES = {
'scrapy_demo.middlewares.ScrapyDemoDownloaderMiddleware': 543,
}
在middlewares.py文件中進行編寫
創建一個中間件:
class DoubanProcess(object):
def process_request(self,request,spider):
request.meta['proxy'] = '你的代理ip地址'
# 需要登錄的話-因為加密需要byte類型,所以需要在前面加b
name_pwd = b'用戶名:密碼'
# 對用戶名密碼加密
encode_name_pwd = base64.b64decode(name_pwd)
# 設置http頭
request.headers['Proxy-Authorization'] = 'Bisic ' + encode_name_pwd.decode()
將你的中間件添加到settings.py的DOWNLOADER_MIDDLEWARES配置中
DOWNLOADER_MIDDLEWARES = {
# 'scrapy_demo.middlewares.ScrapyDemoDownloaderMiddleware': 543,
'scrapy_demo.middlewares.DoubanProcess': 543,
}
設置隨機User-Agent
在middlewares.py文件中進行編寫
創建一個中間件:
class DoubanUserAgent(object):
def process_request(self,request,spider):
# user-agent列表
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)'
]
# 使用random隨機從列表中選擇一個user-agent
agent = random.choice(USER_AGENT_LIST)
# 修改請求頭
request.headers['User_Agent'] = agent
將user-agent中間件添加到 settings.py的DOWNLOADER_MIDDLEWARES配置中(優先級不能相同)
DOWNLOADER_MIDDLEWARES = {
# 'scrapy_demo.middlewares.ScrapyDemoDownloaderMiddleware': 543,
'scrapy_demo.middlewares.DoubanProcess': 543,
'scrapy_demo.middlewares.DoubanUserAgent': 544,
}