python爬取豆瓣电影top250_Python爬虫 - scrapy - 爬取豆瓣电影TOP250
0.前言
新接觸爬蟲,經過一段時間的實踐,寫了幾個簡單爬蟲,爬取豆瓣電影的爬蟲例子網上有很多,但都很簡單,大部分只介紹了請求頁面和解析部分,對于新手而言,我希望能夠有一個比較全面的實例。所以找了很多實例和文章,并整合在一起,在現有豆瓣爬蟲的基礎上,增加了一些內容,算是比較全的內容了。主要包括項目建立、請求頁面、xpath解析、自動翻頁、數據輸出、編碼處理等等。。
系統環境
System Version:Ubuntu 16.04
Python Version:3.5.2
Scrapy Version:1.5.0
1.建立項目
執行如下命令建立scrapy爬蟲項目
scrapy startproject spider_douban
命令執行完成后,建立了spider_douban文件夾,目錄結構如下:
.
├── scrapy.cfg
└── spider_douban
├── __init__.py
├── items.py
├── middlewares.py
├── pipelines.py
├── settings.py
└── spiders
├── douban_spider.py
└── __init__.py
2.建立爬蟲數據模型
打開./spider_douban/items.py文件,編輯內容如下:
import scrapy
class DoubanMovieItem(scrapy.Item):
# 排名
ranking = scrapy.Field()
# 電影名稱
movie_name = scrapy.Field()
# 評分
score = scrapy.Field()
# 評論人數
score_num = scrapy.Field()
3.新建爬蟲文件
新建./spiders/douban_spider.py文件,編輯內容如下:
from scrapy import Request
from scrapy.spiders import Spider
from spider_douban.items import DoubanMovieItem
class DoubanMovieTop250Spider(Spider):
name = 'douban_movie_top250'
start_urls = {
'https://movie.douban.com/top250'
}
'''
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
}
def start_requests(self):
url = 'https://movie.douban.com/top250'
yield Request(url, headers=self.headers)
'''
def parse(self, response):
item = DoubanMovieItem()
movies = response.xpath('//ol[@class="grid_view"]/li')
print(movies)
print('=============================================')
for movie in movies:
item['ranking'] = movie.xpath(
'.//div[@class="pic"]/em/text()').extract()[0]
item['movie_name'] = movie.xpath(
'.//div[@class="hd"]/a/span[1]/text()').extract()[0]
item['score'] = movie.xpath(
'.//div[@class="star"]/span[@class="rating_num"]/text()'
).extract()[0]
item['score_num'] = movie.xpath(
'.//div[@class="star"]/span/text()').re(r'(\d+)人評價')[0]
yield item
next_url = response.xpath('//span[@class="next"]/a/@href').extract()
if next_url:
next_url = 'https://movie.douban.com/top250' + next_url[0]
yield Request(next_url)
爬蟲文件各部分功能記錄
douban_spider.py文件主要有幾部分構成。
導入模塊
from scrapy import Request
from scrapy.spiders import Spider
from spider_douban.items import DoubanMovieItem
Request類用于請求要爬取的頁面數據
Spider類是爬蟲的基類
DoubanMovieItem是我們第一步建立的爬取數據模型
初始設置
基于spider類定義的爬蟲類DoubanMovieTop250Spider中,首先定義爬蟲的基本信息:
name:在項目中爬蟲的名稱,可以在項目目錄中執行scrapy list獲取已經定義的爬蟲列表
start_urls:是爬取的第一個頁面地址
headers:是向web服務器發送頁面請求的時候附加的user-agent消息,告訴web服務器是什么類型的瀏覽器或設備在請求頁面,對于不具備簡單反爬機制的網站,headers部分可以省略。
為了迷惑web服務器,一般會在爬蟲發送web請求的時候定義user-agent信息,這里有兩種寫法。
header的第一種定義:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
}
def start_requests(self):
url = 'https://movie.douban.com/top250'
yield Request(url, headers=self.headers)
可以看到,這種寫法中,start_urls定義沒有了,轉而定義了start_requests函數,開始的url寫到了函數里。同時,定義了headers字典,在發送Request請求的時候,將headers字典一并發送。這種寫法簡單直觀,缺點是在一個爬蟲項目執行期間,所有請求都是一個User-Agent屬性。
header的第二種定義:
start_urls = {
'https://movie.douban.com/top250'
}
簡單、直接的定義start_urls屬性,而Request中的header屬性通過其他方法另外定義,容后再說。
parse處理函數
逐句分解說明
1.基于我們定義的DoubanMovieItem類創建item實例
item = DoubanMovieItem()
2.解析頁面 - 獲取內容框架
通過分析頁面源碼,我們能夠看到,頁面中的電影信息是保存在了
movies = response.xpath('//ol[@class="grid_view"]/li')
3.解析頁面 - 獲取分項
在每一個
首先看看
可以看到要提取數據的各部分所在標簽位置:
排名:class屬性為pic的
標簽下,,標簽中...電影名:class屬性為hd的
標簽下,標簽中的第一個標簽...評分:class屬性為star的
標簽下,class屬性為rating_num的標簽中...評論人數:class屬性為star的
標簽下,標簽中。由于使用了re正則表達式,所以沒有特別指定是哪一個標簽。回到代碼部分,對之前定義的movies做迭代,逐項獲取要抓取的數據。
for movie in movies:
item['ranking'] = movie.xpath(
'.//div[@class="pic"]/em/text()').extract()[0]
item['movie_name'] = movie.xpath(
'.//div[@class="hd"]/a/span[1]/text()').extract()[0]
item['score'] = movie.xpath(
'.//div[@class="star"]/span[@class="rating_num"]/text()'
).extract()[0]
item['score_num'] = movie.xpath(
'.//div[@class="star"]/span/text()').re(r'(\d+)人評價')[0]
yield item
4.Url跳轉(翻頁)
如果到此為止,我們可以將https://movie.douban.com/top250頁面中的第一頁內容爬取到,但只有25項記錄,要爬取全部的250條記錄,就要執行下面代碼:
next_url = response.xpath('//span[@class="next"]/a/@href').extract()
if next_url:
next_url = 'https://movie.douban.com/top250' + next_url[0]
yield Request(next_url)
首先通過xpath解析了頁面中后頁的鏈接,并賦值給next_url變量,如果我們當前在第一頁,那么解析后頁的鏈接就是?start=25&filter=。將解析的后頁鏈接與完整url連接形成完整的地址,再次執行Request(),就實現了對全部250條記錄的爬取。注意:通過xpath解析出的結果是列表,所以在引用的時候寫成next_url[0]。
4.處理隨機Head屬性(隨機User-Agent)
實現隨機的head屬性發送。主要改兩個文件:
settings.py
USER_AGENT_LIST = [
'zspider/0.9-dev http://feedback.redkolibri.com/',
'Xaldon_WebSpider/2.0.b1',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) Speedy Spider (http://www.entireweb.com/about/search_tech/speedy_spider/)',
'Mozilla/5.0 (compatible; Speedy Spider; http://www.entireweb.com/about/search_tech/speedy_spider/)',
'Speedy Spider (Entireweb; Beta/1.3; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Entireweb; Beta/1.2; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Entireweb; Beta/1.1; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Entireweb; Beta/1.0; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Beta/1.0; www.entireweb.com)',
'Speedy Spider (http://www.entireweb.com/about/search_tech/speedy_spider/)',
'Speedy Spider (http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (http://www.entireweb.com)',
'Sosospider+(+http://help.soso.com/webspider.htm)',
'sogou spider',
'Nusearch Spider (www.nusearch.com)',
'nuSearch Spider (compatible; MSIE 4.01; Windows NT)',
'lmspider (lmspider@scansoft.com)',
'lmspider lmspider@scansoft.com',
'ldspider (http://code.google.com/p/ldspider/wiki/Robots)',
'iaskspider/2.0(+http://iask.com/help/help_index.html)',
'iaskspider',
'hl_ftien_spider_v1.1',
'hl_ftien_spider',
'FyberSpider (+http://www.fybersearch.com/fyberspider.php)',
'FyberSpider',
'everyfeed-spider/2.0 (http://www.everyfeed.com)',
'envolk[ITS]spider/1.6 (+http://www.envolk.com/envolkspider.html)',
'envolk[ITS]spider/1.6 ( http://www.envolk.com/envolkspider.html)',
'Baiduspider+(+http://www.baidu.com/search/spider_jp.html)',
'Baiduspider+(+http://www.baidu.com/search/spider.htm)',
'BaiDuSpider',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0) AddSugarSpiderBot www.idealobserver.com',
]
DOWNLOADER_MIDDLEWARES = {
'spider_douban.middlewares.RandomUserAgentMiddleware': 400,
'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
}
USER_AGENT_LIST定義了一些瀏覽器user-agent屬性,網上有很多,可以找來直接加進去,需要注意的是有些user-agent信息是移動設備(手機或平板)的,如果不注意的話,可能請求到的數據與你看到的數據有較大差異;
DOWNLOADER_MIDDLEWARES定義了下載器中間件,它在發送頁面請求數據的時候被調用。
middlewares.py
from spider_douban.settings import USER_AGENT_LIST
import random
class RandomUserAgentMiddleware():
def process_request(self, request, spider):
ua = random.choice(USER_AGENT_LIST)
if ua:
request.headers.setdefault('User-Agent', ua)
在RandomUserAgentMiddleware()中,每次發送請求數據,會在USER_AGENT_LIST中隨機選擇一條User-Agent記錄。
5.結果保存
編輯pipelines.py文件:
from scrapy import signals
from scrapy.contrib.exporter import CsvItemExporter
class SpiderDoubanPipeline(CsvItemExporter):
def __init__(self):
self.files = {}
@classmethod
def from_crawler(cls, crawler):
print('==========pipeline==========from_crawler==========')
pipeline = cls()
crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
return pipeline
def spider_opened(self, spider):
savefile = open('douban_top250_export.csv', 'wb+')
self.files[spider] = savefile
print('==========pipeline==========spider_opened==========')
self.exporter = CsvItemExporter(savefile)
self.exporter.start_exporting()
def spider_closed(self, spider):
print('==========pipeline==========spider_closed==========')
self.exporter.finish_exporting()
savefile = self.files.pop(spider)
savefile.close()
def process_item(self, item, spider):
print('==========pipeline==========process_item==========')
print(type(item))
self.exporter.export_item(item)
return item
SpiderDoubanPipeline類是建立項目的時候自行建立的,為了保存文件,做了修改。
def from_crawler(cls, crawler):
如果存在,則調用此類方法從Crawler創建pipeline實例。它必須返回一個新的pipeline實例。抓取對象提供對所有Scrapy核心組件的訪問,如settings和signals; 這是pipeline訪問它們并將其功能掛接到Scrapy的一種方式。
在此方法中,定義了一個數據收集器(cls)的實例:‘pipeline’。
signals:Scrapy使用信號來通知事情發生。您可以在您的Scrapy項目中捕捉一些信號(使用 extension)來完成額外的工作或添加額外的功能,擴展Scrapy。雖然信號提供了一些參數,不過處理函數不用接收所有的參數 - 信號分發機制(singal dispatching mechanism)僅僅提供處理器(handler)接受的參數。您可以通過 信號(Signals) API 來連接(或發送您自己的)信號。
connect:鏈接一個接收器函數(receiver function) 到一個信號(signal)。signal可以是任何對象,雖然Scrapy提供了一些預先定義好的信號。
def spider_opened(self, spider):
當spider開始爬取時發送該信號。該信號一般用來分配spider的資源,不過其也能做任何事。該信號支持返回deferreds。
此方法中,創建了一個文件對象實例:savefile。
CsvItemExporter(savefile):輸出 csv 文件格式. 如果添加 fields_to_export 屬性, 它會按順序定義CSV的列名.
def spider_closed(self, spider):
當某個spider被關閉時,該信號被發送。該信號可以用來釋放每個spider在 spider_opened 時占用的資源。該信號支持返回deferreds。
def process_item(self, item, spider):
每個item pipeline組件都需要調用該方法,這個方法必須返回一個 Item (或任何繼承類)對象, 或是拋出 DropItem 異常,被丟棄的item將不會被之后的pipeline組件所處理。
啟用pipeline
為了讓我們定義的pipeline生效,要在settings.py文件中,打開ITEM_PIPELINES注釋:
ITEM_PIPELINES = {
'spider_douban.pipelines.SpiderDoubanPipeline': 300,
}
6.執行爬蟲
scrapy crawl douban_movie_top250
執行爬蟲能夠看到爬取到的數據。。。
如果之前pipeline部分代碼沒有寫,也可以用下面的命令,在爬蟲執行的時候直接導出數據:
scrapy crawl douban_movie_top250 -o douban.csv
增加-o參數,可以將爬取到的數據保存到douban.csv文件中。。
7.文件編碼的問題
我在linux服務器執行爬蟲,生成csv文件后,在win7系統中用excel打開變成亂碼。在網上找了一些文章,有的文章直接改變linux文件默認編碼,但是感覺這么做會對其他項目產生影響。最后選擇一個相對簡單的方式。按這幾步執行就可以:
不要直接用excel打開csv文件。先打開excel,建立空白工作表。
選擇數據選項卡,打開獲取外部數據中的自文本。
在導入文本文件對話框中選擇要導入的csv文件。
在文本導入向導 - 第1步中,設置文件原始格式為65001 : Unicode (UTF-8)
繼續下一步選擇逗號分隔,就可以導入正常文本了。
總結
以上是生活随笔為你收集整理的python爬取豆瓣电影top250_Python爬虫 - scrapy - 爬取豆瓣电影TOP250的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 链表推导式_五--pyth
- 下一篇: python写excel标记文字颜色_p