天天看點

爬取豆瓣電影TP250(文字資訊+儲存圖檔)

思路:

1、豆瓣電影TOP250 url=https://movie.douban.com/top250

2、使用crawlspider擷取250個電影詳情頁url

3、使用xpath解析資料:擷取電影标題、導演、演員、簡介、熱門第一評論、評論人數等詳細資訊

4、儲存250部電影海報圖檔

一、準備工作

建立一個scrapy project:

scrapy startproject DBMOVIE
           

建立spider file

scrapy genspider -t crawl douban douban.com
           

二、建構架構

(1)items.py / 定義item

import scrapy

class DbmovieItem(scrapy.Item):
    Rank = scrapy.Field()
    Title =scrapy.Field()
    Attr =scrapy.Field()
    Actor =scrapy.Field()
    Type_ = scrapy.Field()
    Rating_num =scrapy.Field()
    Time_ =scrapy.Field()
    Short =scrapy.Field()
    Image_url = scrapy.Field()
    Hot_comment = scrapy.Field()
           

(2) spider.py

from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
import time
from DBMOVIE.items import DbmovieItem

class DoubanSpider(CrawlSpider):
    name = 'douban'
    allowed_domains = ['douban.com']
    #豆瓣電影top250共有10頁,将每頁的url都加入start_url清單中
    base_urls = 'https://movie.douban.com/top250?start={}&filter='
    start_urls =[]
    #設定index用來檢視爬取進度,可不要
    index = 0
    for i in range(10):
        url = base_urls.format(i*25)
        start_urls.append(url)
    #設定crawl爬取規則,擷取每頁中的25個詳情頁url
    #CrawlSpider架構擷取url有去重功能
    rules = (
        Rule(LinkExtractor(allow='subject/'), callback='parse_item', follow=False),
    )

    def parse_item(self, response):
        self.index +=1
        #導入item
        item = DbmovieItem()
        #擷取排名,得到的資料順序是随機的,後續可以使用排名重新排序
        item['Rank'] = response.xpath('//*[@id="content"]/div[1]/span[1]/text()').extract_first()[3:]
        #電影名稱
        item['Title'] = response.xpath('//*[@id="content"]/h1/span[1]/text()').extract_first()
        #導演
        item['Attr'] = response.xpath('//*[@id="info"]/span[1]/span[2]/a/text()').extract_first()
        #演員,演員有多個,在多個同級标簽中,使用join将擷取到的清單中多個導演名字連成一個完整字元串
        item['Actor'] = ','.join(response.xpath('//*[@id="info"]/span[@class="actor"]/span[2]/a/text()').extract())
        #電影類别
        item['Type_'] =  ','.join(response.xpath('//*[@id="info"]/span[@property="v:genre"]/text()').extract())
        #電影評論人數
        item['Rating_num'] = response.xpath('//*[@id="interest_sectl"]//a[@class="rating_people"]/span/text()').extract_first()
        #上映時間
        item['Time_'] = ','.join(response.xpath('//*[@id="info"]/span[@property="v:initialReleaseDate"]/text()').extract())
        #簡介
        item['Short'] = (((''.join(response.xpath('//*[@id="link-report"]//span[1]/text()').extract())).replace('\n','')).strip()).replace(' ','')
        #圖檔url,後面用來下載下傳圖檔
        item['Image_url'] = response.xpath('//*[@id="mainpic"]/a/img/@src').extract_first()
        #熱評第一個
        item['Hot_comment'] = (response.xpath('//*[@id="hot-comments"]/div[1]/div/p/span/text()').extract_first().strip()).replace('\t','')
        print('擷取到第%d個' % self.index)
        print(item['Rank'],item['Title']) 
        yield item
           

(3) middlewares.py

#在項目下建立了一個user_agent.py檔案儲存了user_agents池
#使用scrapy的UserAgentMiddleware子產品擷取user_agent
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
from DBMOVIE.user_agent import user_agents
import random

class RotateUserAgentMiddleware(UserAgentMiddleware):

    def process_request(self, request, spider):
    	#随機選取一個user_agent,傳入請求頭
        user_agent = random.choice(user_agents)
        if user_agent:
            print('**********user ug:%s***********' % user_agent)
            request.headers['User-Agent'] = user_agent
        return None
           

(4)pipelines.py

from scrapy.exporters import CsvItemExporter
import DBMOVIE.settings as setting
import urllib.request
import os
import pymongo
#将擷取的資料儲存到MongoDB資料庫中
class DbmoviePipeline(object):
    def open_spider(self,spider):
    	#連接配接伺服器,使用預設位址端口
        self.client = pymongo.MongoClient()
        #建立/選擇資料庫
        self.mydb = self.client['test']
        #建立/選擇表
        self.collection = self.mydb['dbmovie']

    def process_item(self, item, spider):
        #插入資料
        self.collection.insert(dict(item))
        return item


#重寫一個儲存圖檔的管道
class DbmovieImgPipline(object):

    def process_item(self,item,spider):
		#設定儲存圖檔的檔案夾位址
        dir_path = '%s/%s' % (setting.IMAGES_STORE,spider.name)
        #若不存在則建立它
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
        #擷取圖檔url
        img_url = item['Image_url']
        #建立圖檔名稱
        file_name = item['Rank'] + item['Title'] + '.jpg'
        #拼接檔案夾位址和圖檔名稱建立檔案儲存路徑
        file_path = '%s/%s' % (dir_path,file_name)
        #去重
        if os.path.exists(file_path):
            print('重複,跳過',+img_url)
        #儲存圖檔
        with open(file_path,'wb') as f:
            print('正在下載下傳圖檔',img_url)
            #使用圖檔url發生請求擷取到圖檔,儲存到對應的路徑中
            conn = urllib.request.urlopen(img_url)
            f.write(conn.read())
            f.close()
        return item
           

5)設定setting

一般寫好一部分代碼就開啟相應的設定,以防忘記

BOT_NAME = 'DBMOVIE'

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

LOG_FILE = 'douban.log'
LOG_LEVEL = 'WARNING'
#儲存圖檔的檔案位址
IMAGES_STORE = './img'
#不遵守robort協定
ROBOTSTXT_OBEY = False
#下載下傳延遲
DOWNLOAD_DELAY = 3
#打開設定user_agent的下載下傳中間件
DOWNLOADER_MIDDLEWARES = {
   'DBMOVIE.middlewares.RotateUserAgentMiddleware': 543,
}
#打開儲存資料和圖檔的管道
ITEM_PIPELINES = {
   'DBMOVIE.pipelines.DbmoviePipeline': 300,
    'DBMOVIE.pipelines.DbmovieImgPipline':350,
}
           

三、運作spider

(1)打開MongoDB伺服器,啟動用戶端

sudo mongod
           
mongo
           

(2)運作spider

scrapy crawl maitian
           

四、完成以上幾步即可以檢視資料啦

如果需要可以對MongoDB中的資料CSV可視化處理

爬取豆瓣電影TP250(文字資訊+儲存圖檔)
爬取豆瓣電影TP250(文字資訊+儲存圖檔)