Scrapy安裝、爬蟲入門教程、爬蟲實例(豆瓣電影爬蟲)


Scrapy在window上的安裝教程見下面的鏈接:Scrapy安裝教程

上述安裝教程已實踐,可行。(本來打算在ubuntu上安裝Scrapy的,但是Ubuntu 磁盤空間太少了,還沒擴展磁盤空間,所以沒有在Ubuntu上裝,至於如何在Ubuntu上安裝Scrapy,網上有挺多教程的)

Scrapy的入門教程見下面鏈接:Scrapy入門教程

上面的入門教程是很基礎的,先跟着作者走一遍,要動起來喲,不要只是閱讀上面的那篇入門教程。

下面我簡單總結一下Scrapy爬蟲過程:

1、在Item中定義自己要抓取的數據

movie_name就像是字典中的“鍵”,爬到的數據就像似字典中的“值”。在繼承了BaseSpider的類中會用到:

第一行就是上面那個圖中的TutorialItem這個類,紅框圈出來的就是上圖中的movie_name這個變量

2、然后在spiders目錄下編輯Spider.py那個文件

按上面【入門教程】來寫就行了,我這邊給個例子,跟我上面的item是匹配的:

【入門教程】你沒有給出start_requests這個方法,稍后我會講到這個方法。另外這里的代碼我都是截圖,后面我會用代碼面板顯示我的代碼,有需要的人可以復制下來玩玩。

3、編輯pipelines.py文件,可以通過它將保存在TutorialItem中的內容寫入到數據庫或者文件中

下面的代碼示例是寫到文件(如果要寫到數據庫中去,這里有個示例代碼)中去:

對json模塊的方法的注釋:dump和dumps(從Python生成JSON),load和loads(解析JSON成Python的數據類型);dump和dumps的唯一區別是dump會生成一個類文件對象,dumps會生成字符串,同理load和loads分別解析類文件對象和字符串格式的JSON。(注釋來於http://www.jb51.net/article/52224.htm )

4、爬蟲開始

上述三個過程后就可以爬蟲了,僅需上述三個過程喲,然后在dos中將目錄切換到tutorial下輸入scrapy crawl douban就可以爬啦:

上面幾個過程只是先理清楚用Scrapy爬蟲的思路,下面的重點戲是第二個過程,我會對這個過程進行較詳細的解釋,並提供代碼。

douban_spider.py這個文件的代碼如下:

  1 #coding=utf-8
  2 import sys
  3 reload(sys)
  4 #python默認環境編碼時ascii
  5 sys.setdefaultencoding("utf-8")
  6 from scrapy.spider import BaseSpider
  7 from scrapy.http import Request
  8 from scrapy.selector import HtmlXPathSelector
  9 from tutorial.items import TutorialItem
 10 import re
 11 
 12 class DoubanSpider(BaseSpider):
 13     name = "douban"
 14     allowed_domains = ["movie.douban.com"]
 15     start_urls = []
 16 
 17     def start_requests(self):
 18         file_object = open('movie_name.txt','r')
 19 
 20         try:
 21             url_head = "http://movie.douban.com/subject_search?search_text="
 22             for line in file_object:
 23                 self.start_urls.append(url_head + line)
 24             
 25             for url in self.start_urls:
 26                 yield self.make_requests_from_url(url)
 27         finally:
 28             file_object.close()
 29             #years_object.close()
 30 
 31     def parse(self, response):
 32         #open("test.html",'wb').write(response.body)
 33         hxs = HtmlXPathSelector(response)
 34         #movie_name = hxs.select('//*[@id="content"]/div/div[1]/div[2]/table[1]/tr/td[1]/a/@title').extract()
 35         movie_link = hxs.select('//*[@id="content"]/div/div[1]/div[2]/table[1]/tr/td[1]/a/@href').extract()
 36         #movie_desc = hxs.select('//*[@id="content"]/div/div[1]/div[2]/table[1]/tr/td[2]/div/p/text()').extract()
 37 
 38         if movie_link:
 39             yield Request(movie_link[0],callback=self.parse_item)
 40         
 41         
 42     def parse_item(self,response):
 43         hxs = HtmlXPathSelector(response)
 44         movie_name = hxs.select('//*[@id="content"]/h1/span[1]/text()').extract()
 45         movie_director = hxs.select('//*[@id="info"]/span[1]/span[2]/a/text()').extract()
 46         movie_writer = hxs.select('//*[@id="info"]/span[2]/span[2]/a/text()').extract()
 47         #爬取電影詳情需要在已有對象中繼續爬取
 48         movie_description_paths = hxs.select('//*[@id="link-report"]')
 49         movie_description = []
 50         for movie_description_path in movie_description_paths:
 51             movie_description = movie_description_path.select('.//*[@property="v:summary"]/text()').extract()
 52 
 53         #提取演員需要從已有的xPath對象中繼續爬我要的內容
 54         movie_roles_paths = hxs.select('//*[@id="info"]/span[3]/span[2]')
 55         movie_roles = []
 56         for movie_roles_path in movie_roles_paths:
 57             movie_roles = movie_roles_path.select('.//*[@rel="v:starring"]/text()').extract()
 58 
 59         #獲取電影詳細信息序列
 60         movie_detail = hxs.select('//*[@id="info"]').extract()
 61 
 62         item = TutorialItem()
 63         item['movie_name'] = ''.join(movie_name).strip().replace(',',';').replace('\'','\\\'').replace('\"','\\\"').replace(':',';')
 64         #item['movie_link'] = movie_link[0]
 65         item['movie_director'] = movie_director[0].strip().replace(',',';').replace('\'','\\\'').replace('\"','\\\"').replace(':',';') if len(movie_director) > 0 else ''
 66         #由於逗號是拿來分割電影所有信息的,所以需要處理逗號;引號也要處理,否則插入數據庫會有問題
 67         item['movie_description'] = movie_description[0].strip().replace(',',';').replace('\'','\\\'').replace('\"','\\\"').replace(':',';') if len(movie_description) > 0 else ''
 68         item['movie_writer'] = ';'.join(movie_writer).strip().replace(',',';').replace('\'','\\\'').replace('\"','\\\"').replace(':',';')
 69         item['movie_roles'] = ';'.join(movie_roles).strip().replace(',',';').replace('\'','\\\'').replace('\"','\\\"').replace(':',';')
 70         #item['movie_language'] = movie_language[0].strip() if len(movie_language) > 0 else ''
 71         #item['movie_date'] = ''.join(movie_date).strip()
 72         #item['movie_long'] = ''.join(movie_long).strip()
 73         
 74         #電影詳情信息字符串
 75         movie_detail_str = ''.join(movie_detail).strip()
 76         #print movie_detail_str
 77 
 78         movie_language_str = ".*語言:</span> (.+?)<br><span.*".decode("utf8")
 79         movie_date_str = ".*上映日期:</span> <span property=\"v:initialReleaseDate\" content=\"(\S+?)\">(\S+?)</span>.*".decode("utf8")
 80         movie_long_str = ".*片長:</span> <span property=\"v:runtime\" content=\"(\d+).*".decode("utf8")
 81         
 82         pattern_language =re.compile(movie_language_str,re.S)
 83         pattern_date = re.compile(movie_date_str,re.S)
 84         pattern_long = re.compile(movie_long_str,re.S)
 85         
 86         
 87         movie_language = re.search(pattern_language,movie_detail_str)
 88         movie_date = re.search(pattern_date,movie_detail_str)
 89         movie_long = re.search(pattern_long,movie_detail_str)
 90 
 91         item['movie_language'] = ""
 92         if movie_language:
 93             item['movie_language'] = movie_language.group(1).strip().replace(',',';').replace('\'','\\\'').replace('\"','\\\"').replace(':',';')
 94         #item['movie_detail'] = ''.join(movie_detail).strip()
 95 
 96         item['movie_date'] = ""
 97         if movie_date:
 98             item['movie_date'] = movie_date.group(1).strip().replace(',',';').replace('\'','\\\'').replace('\"','\\\"').replace(':',';')
 99 
100         item['movie_long'] = ""
101         if movie_long:
102             item['movie_long'] = movie_long.group(1)
103 
104         yield item
douban_spider.py

代碼有了,我來一步步講解哈。

前言:我要爬的是豆瓣的數據,我有了很多電影的名字,但是我需要電影的詳情,我用了一下豆瓣電影的網站,發現當我在搜索框里輸入“Last Days in Vietnam”時url會變成http://movie.douban.com/subject_search?search_text=Last+Days+in+Vietnam&cat=1002 然后我就試着直接輸入http://movie.douban.com/subject_search?search_text=Last+Days+in+Vietnam這個url,搜索結果是一樣的,很顯然這就是get方式,這樣我們就找到了規律:http://movie.douban.com/subject_search?search_text=后面加上我們的電影名字並用加號分割就行了。

我們的電影名字(大量的電影名字)是存在movie_name.txt這個文件中里面的(一行一個電影名字):

我們可以先用python腳本(shell腳本也行)將電影名之間的空格處理為+,也可以在爬蟲中讀取電影名后進行一次replace處理(我是先處理成+的)。爬蟲讀取電影名字文件,然后構建url,然后就根據得到的網頁找到搜索到的第一個電影的url(其實第一個電影未必一定是我們要的,但是這種情況是少數,我們暫時不理會它),得到第一個電影的url后,再繼續爬,這次爬到的頁面就含有我們想要的電影信息,需要使用XPath來獲得html文件中元素節點,最后將獲得的信息存到TutorialItem中,通過pipelines寫入到data.dat文件中

XPath的教程在這里:w3school的基礎教程scrapy官網上的Xpath 這些東西【入門教程】中都有說。

1、start_requests方法:

在【入門教程】那篇文章中沒有用到這個方法,而是直接在start_urls中存入我們要爬蟲的網頁鏈接,但是如果我們要爬蟲的鏈接很多,而且是有一定規律的,我們就需要重寫這個方法了,首先我們看看start_requests這個方法是干嘛的:

可見它就是從start_urls中讀取鏈接,然后使用make_requests_from_url生成Request,

start_requests官方解釋在這里

那么這就意味我們可以在start_requests方法中根據我們自己的需求往start_urls中寫入我們自定義的規律的鏈接:

2、parse方法:

 生成了請求后,scrapy會幫我們處理Request請求,然后獲得請求的url的網站的響應response,parse就可以用來處理response的內容。在我們繼承的類中重寫parse方法:

parse_item是我們自定義的方法,用來處理新連接的request后獲得的response:

遞歸爬蟲的方法這里這里有。

HtmlXPathSelector的解釋在這里

為了獲得我想要的數據我也是蠻拼的,由於豆瓣電影詳情的節點是沒太大規律了,我后面還用了正則表達式去獲取我要的內容,具體看上面的代碼中parse_item這個方法吧:

好了,結束了,這里還有一篇Scrapy的提高篇,有興趣的去看看吧。

寫寫博客是為了記錄一下自己實踐的過程,也希望能對需要者有用吧!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM