Python日記:基於Scrapy的爬蟲實現,pythonscrapy
安裝 pywin32 和python版本一致
地址 https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/
安裝過程中提示找不到Python2.7
解決方案:http://blog.csdn.net/pppii/article/details/48679403
安裝Scrapy 使用pip
1、使用命令列建立爬蟲項目
scrapy startproject myspider # cmd進入指定檔案夾後建立一個名為 myspider的爬蟲
2、啟動pyCharm
開啟項目 myspider ,在檔案夾spiders下建立MySprider.py檔案
添加我的爬蟲 class Channel9Spider(scrapy.Spider):
name 表示爬蟲的名稱 屬於唯一屬性
allowed_domins=[] 爬蟲允許的網域
start_urls=[] 爬蟲開始的頁面
def parse(self,response): 訪問地址後調用的方法
def details_parse(self,response): 處理詳情頁面的方法
MySprider.py遇到的問題:
1、windows命令提示字元中列印爬取的檔案名稱報錯
原因:是命令列字元集和網頁字元集不一致
處理方法:print item["title"].encode("gbk","ignore")
2、回調方法報錯
原因:PyScrapy預設給回調加了個括弧
處理方法:去掉回調方法後的括弧,需要傳參使用Request(url=.. , meta={'name':'yancl',....},calback=self.details_parse,dont_filter=True)
3、提示訪問被拒絕
原因:1、robots 協議問題 2、由於設定了允許爬取的域
處理方法:1、修改settings.py 設定ROBOTSTXT_OBEY = True
2、調用Request方法設定dont_filter=True
開啟 items.py
添加在處理頁面後要傳遞給pipeline的item資料對象
用到了下載所以添加 file_urls,files,file_paths
開啟 pipeline.py
1、添加一個繼承FilesPipeline檔案下載管道的實現方法 MyFilesPipeline
2、添加一個記錄檔案方法 JsonWithEncodingPipeline
開啟settings.py
1、啟用我的Item Pipeline組建。我打算下載一個視頻就記錄一條對應的Json資訊
2、添加視頻下載儲存檔案的路徑
再次啟動爬蟲 scrapy crawl myspider
遇到的問題:
1、下載檔案過大
2、連線逾時
3、檔案下載的路徑問題,預設添加full的檔案夾
4、檔案名稱問題
對於問題1、2、3 修改settings
DOWNLOAD_MAXSIZE = 325674803 #位元組
DOWNLOAD_WARNSIZE = 325674803 #位元組
DOWNLOAD_TIMEOUT = 30 * 60 #單位秒
FILES_STORE = "F:\\mp4files" #直接使用絕對路徑
對於問題3,修改MyFilesPipeline方法 重寫file_path方法
再次啟動爬蟲運行正常,但是還有2個小問題,1、有一個檔案自動添加了檔案夾 2、有幾個檔案沒有尾碼大小為0KB
根據日誌分析是檔案名稱導致了 檔案名稱中不能有:/ 等特殊字元
MySpider.py
import scrapyfrom mydemo.items import MydemoItemfrom scrapy.http import Requestfrom scrapy.selector import Selectordownload_domain = "https://channel9.msdn.com"class Channel9Spider(scrapy.Spider): name = "myspider" allowed_domains = [".msdn.com"] start_urls = [ "https://channel9.msdn.com/Events/Ignite/Microsoft-Ignite-China-2016?sort=status&direction=desc" ] def parse(self,response): sale = Selector(response) for a in sale.xpath("//h3"): title = a.xpath("a/text()").extract()[0] line = a.xpath("a/@href").extract()[0] fileurl = download_domain + line yield Request(url=fileurl,meta={'title':title},callback=self.details_parse,dont_filter=True) next_page = sale.xpath("//a[@rel='next']/@href").extract() if next_page: pagepath = download_domain+next_page[0] yield Request(url=pagepath,callback=self.parse,dont_filter=True) def details_parse(self,response): sale = Selector(response) item = MydemoItem() item["title"] = response.meta['title'] fileurl = sale.xpath("//*[@id='format']/option/@value").extract()[0] item["file_urls"] = [fileurl] yield item
items.py
class MydemoItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() link = scrapy.Field() content = scrapy.Field() file_urls = scrapy.Field() files = scrapy.Field() file_paths = scrapy.Field() pass
pipelines.py
# -*- coding: utf-8 -*-# Define your item pipelines here## Don't forget to add your pipeline to the ITEM_PIPELINES setting# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.htmlimport scrapyimport codecsimport jsonimport timefrom scrapy.pipelines.files import FilesPipelinefrom scrapy.exceptions import DropItemclass MydemoPipeline(object): def process_item(self, item, spider): return itemclass JsonWithEncodingPipeline(object): def __init__(self): self.file = codecs.open('file.json','w',encoding='utf-8') def process_item(self,item,spider): timeSatamp = time.time() timeTuple = time.localtime(timeSatamp) curTime = time.strftime("%Y-%m-%d %H:%M:%S",timeTuple) line = "["+curTime+"] "+json.dumps(dict(item),ensure_ascii=False)+"\n" self.file.write(line) return item def spider_closed(self,spider): self.file.close()class MyFilesPipeline(FilesPipeline): def get_media_requests(self,item,info): for file_url in item['file_urls']: yield scrapy.Request(file_url,meta={'title':item['title']}) def item_completed(self, results, item, info): file_paths = [x['path'] for ok, x in results if ok] if not file_paths: raise DropItem("Item contains no Files") item["file_paths"] = file_paths return item def file_path(self,request,response=None,info=None): title = request.meta['title'] file_guid = title + '.'+request.url.split('/')[-1].split('.')[-1] filename = u'{0}'.format(file_guid) return filename
settings.py
產生的日誌如下:
爬取的檔案: