python網絡爬蟲之使用scrapy下載文件


前面介紹了ImagesPipeline用於下載圖片,Scrapy還提供了FilesPipeline用與文件下載。和之前的ImagesPipeline一樣,FilesPipeline使用時只需要通過item的一個特殊字段將要下載的文件或圖片的url傳遞給它們,它們便會自動將文件或圖片下載到本地。將下載結果信息存入item的另一個特殊字段,便於用戶在導出文件中查閱。工作流程如下:

1 在一個爬蟲里,你抓取一個項目,把其中圖片的URL放入 file_urls 組內。

2 項目從爬蟲內返回,進入項目管道。

3 當項目進入 FilesPipeline,file_urls 組內的URLs將被Scrapy的調度器和下載器(這意味着調度器和下載器的中間件可以復用)安排下載,當優先級更高,會在其他頁面被抓取前處理。項目會在這個特定的管道階段保持“locker”的狀態,直到完成文件的下載(或者由於某些原因未完成下載)。

4 當文件下載完后,另一個字段(files)將被更新到結構中。這個組將包含一個字典列表,其中包括下載文件的信息,比如下載路徑、源抓取地址(從 file_urls 組獲得)和圖片的校驗碼(checksum)。 files 列表中的文件順序將和源 file_urls 組保持一致。如果某個圖片下載失敗,將會記錄下錯誤信息,圖片也不會出現在 files 組中。

下面來看下如何使用:

第一步:在配置文件settings.py中啟用FilesPipeline

ITEM_PIPELINES = {
    'scrapy.pipelines.files.FilesPipeline':1,
}

第二步:在配置文件settings.py中設置文件下載路徑

FILE_STORE='E:\scrapy_project\file_download\file'

第三步:在item.py中定義file_url和file兩個字段
class FileDownloadItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
file_urls=scrapy.Field()
files=scrapy.Field()

這三步設置后以后,下面就來看下具體的下載了,我們從matplotlib網站上下載示例代碼。網址是:http://matplotlib.org/examples/index.html

接下來來查看網頁結構,如下

點擊animate_decay后進入下載頁面。Animate_decay的網頁鏈接都在<div class=”toctree-wrapper compound”>元素下。

但是像animation Examples這種索引的鏈接我們是不需要的

通過這里我們可以首先寫出我們的網頁獲取鏈接的方式:

def parse(self,response):
le=LinkExtractor(restrict_xpaths='//*[@id="matplotlib-examples"]/div',deny='/index.html$')
for link in le.extract_links(response):
yield Request(link.url,callback=self.parse_link)

restrict_xpaths設定網頁鏈接的元素。Deny將上面的目錄鏈接給屏蔽了。因此得到的都是具體的文件的下載鏈接

接下來進入下載頁面,網頁結構圖如下:點擊source_code就可以下載文件

網頁結構如下

還有另外一種既包含代碼鏈接,又包含圖片鏈接的

從具體的文件下載鏈接來看有如下兩種;

http://matplotlib.org/examples/pyplots/whats_new_99_mplot3d.py

http://matplotlib.org/mpl_examples/statistics/boxplot_demo.py

針對這兩種方式獲取對應的鏈接代碼如下:

def parse_link(self,response):
pattern=re.compile('href=(.*\.py)')
div=response.xpath('/html/body/div[4]/div[1]/div/div')
p=div.xpath('//p')[0].extract()
link=re.findall(pattern,p)[0]
if ('/') in link: #針對包含文件,圖片的下載鏈接方式生成:http://matplotlib.org/examples/pyplots/whats_new_99_mplot3d.py
href='http://matplotlib.org/'+link.split('/')[2]+'/'+link.split('/')[3]+'/'+link.split('/')[4]
else: #針對只包含文件的下載鏈接方式生成:http://matplotlib.org/mpl_examples/statistics/boxplot_demo.py
link=link.replace('"','')
scheme=urlparse(response.url).scheme
netloc=urlparse(response.url).netloc
temp=urlparse(response.url).path
path='/'+temp.split('/')[1]+'/'+temp.split('/')[2]+'/'+link
combine=(scheme,netloc,path,'','','')
href=urlunparse(combine)
# print href,os.path.splitext(href)[1]
file=FileDownloadItem()
file['file_urls']=[href]
return file
運行后出現如下的錯誤:提示ValueError: Missing scheme in request url: h。 
2017-11-21 22:29:53 [scrapy] ERROR: Error processing {'file_urls': u'http://matplotlib.org/examples/api/agg_oo.htmlagg_oo.py'}
Traceback (most recent call last):
  File "E:\python2.7.11\lib\site-packages\twisted\internet\defer.py", line 588, in _runCallbacks
    current.result = callback(current.result, *args, **kw)
  File "E:\python2.7.11\lib\site-packages\scrapy\pipelines\media.py", line 44, in process_item
    requests = arg_to_iter(self.get_media_requests(item, info))
  File "E:\python2.7.11\lib\site-packages\scrapy\pipelines\files.py", line 365, in get_media_requests
    return [Request(x) for x in item.get(self.files_urls_field, [])]
  File "E:\python2.7.11\lib\site-packages\scrapy\http\request\__init__.py", line 25, in __init__
    self._set_url(url)
  File "E:\python2.7.11\lib\site-packages\scrapy\http\request\__init__.py", line 57, in _set_url
    raise ValueError('Missing scheme in request url: %s' % self._url)
ValueError: Missing scheme in request url: h
這個錯誤的意思是在url中丟失了scheme. 我們知道網址的一般結構是:scheme://host:port/path?。 這里的錯誤意思就是在scheme中沒有找到http而只有一個h. 但是從log記錄的來看,我們明明是生成了一個完整的網頁呢。為什么會提示找不到呢。原因就在於下面的這個配置使用的是url列表形式
ITEM_PIPELINES = {
# 'file_download.pipelines.SomePipeline': 300,
'scrapy.pipelines.files.FilesPipeline':1,
}
而我們的代碼對於item的賦值卻是file['file_urls']=href 字符串的形式,因此如果用列表的方式來提取數據,只有h被提取出來了。因此代碼需要成列表的賦值形式。修改為:file['file_urls']=[href]就可以了

 

程序運行成功。從保存路徑來看,在download下面新建了一個full文件夾。然后下載的文件都保存在里面。但是文件名卻是00f4d142b951f072.py這種形式的。這些文件名是由url的散列值的出來的。這種命名方式可以防止重名的文件相互沖突,但是這種文件名太不直觀了,我們需要重新來定義下載的文件名名字

在FilesPipeline中,下載文件的函數是file_path。主體代碼如下

Return的值就是文件路徑。從下面看到是文件都是建立在full文件下面

media_guid = hashlib.sha1(to_bytes(url)).hexdigest()  
media_ext = os.path.splitext(url)[1]
return 'full/%s%s' % (media_guid, media_ext)

media_guid得到的是url的散列值,作為文件名

media_ext得到的是文件的后綴名也就是.py

 

下面我們來重新寫file_path函數用於生成我們自己的文件名

 

我們可以看到有很多網址是下面的形式,widgets是大類。后面的py文件是這個大類下的文件。我們需要將屬於一個大類的文件歸檔到同一個文件夾下面。

http://matplotlib.org/examples/widgets/span_selector.py http://matplotlib.org/examples/widgets/rectangle_selector.py

http://matplotlib.org/examples/widgets/slider_demo.py

http://matplotlib.org/examples/widgets/radio_buttons.py

http://matplotlib.org/examples/widgets/menu.py

http://matplotlib.org/examples/widgets/multicursor.py

http://matplotlib.org/examples/widgets/lasso_selector_demo.py

 

比如網頁為http://matplotlib.org/examples/widgets/span_selector.py

urlparse(request.url).path 得到的結果是examples/widgets/span_selector.py
dirname(path)得到的結果是examples/widgets
basename(dirname(path))得到的結果是widgets
join(basename(dirname(str)),basename(str))得到的結果是widgets\ span_selector.py
重寫pipeline.py如下:
from scrapy.pipelines.files import FilesPipeline
from urlparse import urlparse
from os.path import basename,dirname,join
class FileDownloadPipeline(FilesPipeline):
def file_path(self, request, response=None, info=None):
path=urlparse(request.url).path
temp=join(basename(dirname(path)),basename(path))
return '%s/%s' % (basename(dirname(path)), basename(path))
運行程序發現生成的文件名還是散列值的。原因在於在之前的setting.py中,我們設置的是'scrapy.pipelines.files.FilesPipeline':1
這將會直接采用FilesPipeline。現在我們重寫了FilesPipeline就需要更改這個設置,改為FileDownloadPipeline
ITEM_PIPELINES = {
# 'file_download.pipelines.SomePipeline': 300,
# 'scrapy.pipelines.files.FilesPipeline':1,
'file_download.pipelines.FileDownloadPipeline':1,
}
再次運行,得到如下的結果:同一類的文件都被歸類到了同一個文件夾下面。

且文件名采用的是更直觀的方式。這樣比散列值的文件名看起來直觀多了

matplotlib文件打包的下載鏈接如下,有需要的可以下載

https://files.cnblogs.com/files/zhanghongfeng/matplotlib.rar

scrapy工程代碼如下:

https://files.cnblogs.com/files/zhanghongfeng/file_download.rar

 

 
        

 


免責聲明!

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



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