Scrapy爬蟲框架學習
阿新 • • 發佈:2019-04-06
需求 項目 創建 tps http 分享圖片 contains 創建項目 parse
一、Scrapy框架簡介
1. 下載頁面 2. 解析 3. 並發 4. 深度
二、安裝
linux下安裝 pip3 install scrapy windows下安裝 a.pip3 install wheel b.下載twisted和pywin32 http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted c.進入下載目錄 執行pip3 install Twisted-18.7.0-cp36-cp36m-win_amd64.whl #cp36為適合python3.6執行pip3 install pywin32-224-cp36-cp36m-win_amd64.whl d.pip3 install scrapy e.下載並安裝pywin32:https://sourceforge.net/projects/pywin32/files/ #找到適合本機python版本的64位
三、Scrapy整體架構圖
3.1 Scrapy使用Twisted異步網絡庫來處理網絡通訊
3.2 各個主要文件說明
spiders(蜘蛛)文件夾:如ip138.com
name #不能省略,最好不要修改starts_urls #起始url allowed_domains #爬取允許域名列表,起始url不受影響。網頁中的外鏈受此限制
四、基本使用
1. 指定初始url 2. 解析器響應內容 - 給調度器 - 給item:pipeline;用於做格式化;持久化 基本步驟: a:scrapy startproject 項目名 #創建項目 b:進入項目目錄 c:scrapy genspider baidu www.baidu.com #創建start_url d:打開項目名\spiders\baidu.py進行編輯 e:scrapy crawl baidu#執行,加--nolog可以不顯示日誌,如果沒有內容顯示,可能此IP已經有防爬機制,可換個不知名ip試試
五、篩選器
5.1 Selector介紹
在scrapy中,可以使用Selector篩選器,代替BeautifulSoup
在scrapy項目裏的spiders文件裏的baidu.py爬蟲文件編輯,導入Selecotr模塊
from scrapy.selector import Selector
5.2 Selector(response=response).xpath()基本用法
// #表示子子孫孫,即所有 .// #當前對象的子孫中 / #兒子 /div #兒子中的div標簽 //div[@id] #所有標簽含有id的div標簽 /div[@id=‘i1‘] #兒子中的div且id =‘i1‘的標簽 obj.extract() #列表中每一個對象轉換成字符串 ==>返回的是列表 obj.extract_first() #列表中每一各對象轉換成字符串==>返回的是列表中第一個元素 //div/text() #獲取所有div標簽裏的文本==》返回的是列表,元素是對象 //a/@href #獲取所有a標簽裏的url==》返回的是列表,元素是對象 //a[starts-with(@href,"link")] #獲取所有a標簽,並且href屬性是以link開頭的 //a[re:test(@href,"/sitehome/p/\d+")]/@href #正則,獲取所有a標簽屬性href符合/sitehome/p/數字的 //div[@id=‘i1‘][@href=‘‘xx] #[][]且的意思,即所有含有id=‘i1‘且href=‘xxx‘的div標簽 //a[contains(@href, "link")] #所有href字段包含link字符串的a標簽
5.3 簡單示例
需求:在www.ip138.com網站裏,打印如下a標簽的文本內容和url地址
在爬蟲文件(baidu.py)裏的parse類方法裏編輯
# -*- coding: utf-8 -*- import scrapy from scrapy.selector import Selector class BaiduSpider(scrapy.Spider): name = ‘baidu‘ allowed_domains = [‘ip138.com‘] start_urls = [‘http://www.ip138.com/‘] def parse(self, response): #請求該頁面下所有a標簽==》列表,每個元素都是對象 #找到div標簽裏有class=mod-guide屬性下的所有子孫a標簽裏文本內容 text_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/text()‘) # 找到div標簽裏有class=mod-guide屬性下的所有子孫a標簽裏url url_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/@href‘) #將列表中對象轉化成列表中字符串 text_str_list = text_obj_list.extract() url_str_list = url_obj_list.extract() for a_text,a_url in zip(text_str_list,url_str_list): print(a_text,a_url)代碼
如何運行代碼?
在cmd窗口,進入項目目錄,運行scrapy crawl baidu
5.4 獲取當前網頁中的所有頁碼實例
需求:獲取博客園裏的首頁頁碼url
在爬蟲文件(ip138.py)裏的parse類方法裏編輯
# -*- coding: utf-8 -*- import scrapy from scrapy.selector import Selector class Ip138Spider(scrapy.Spider): name = ‘ip138‘ allowed_domains = [‘www.cnblogs.com‘] start_urls = [‘https://www.cnblogs.com/‘] urls_set = set() def parse(self, response): # text_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/text()‘) # url_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/@href‘) # # text_str_list = text_obj_list.extract() # url_str_list = url_obj_list.extract() # # for text,url in zip(text_str_list,url_str_list): # print(text,url) #獲取當前頁裏的所有頁碼的url對象列表 url_obj_list = Selector(response=response).xpath(‘//div[@class="pager"]/a/@href‘) ##或者2: starts-with(@屬性,‘值開頭‘) #url_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘) ##或者3:正則表達式固定用法re:test(@屬性值,"正則表達式") #url_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘) #將對象列表轉換成字符串列表 url_str_list = url_obj_list.extract() for url in url_str_list: print(url) #1.通過集合去除重復url #2.使用加密的MD5存儲url,好處:加密和等長 url_md5 = self.my_md5(url) if url_md5 not in self.urls_set: self.urls_set.add(url_md5) print(url_md5) else: print(‘%s已經存在‘%url_md5) def my_md5(self,url): import hashlib obj = hashlib.md5() obj.update(bytes(url,encoding=‘utf-8‘)) return obj.hexdigest()代碼
5.5 獲得當前網頁裏的頁碼自動請求爬取實例
需求:自動爬取博客園的所有頁碼(基於5.4案例的基礎)
在爬蟲文件(ip138.py)裏的parse類方法裏編輯
# -*- coding: utf-8 -*- import scrapy from scrapy.selector import Selector from scrapy.http import Request class Ip138Spider(scrapy.Spider): name = ‘ip138‘ allowed_domains = [‘www.cnblogs.com‘] start_urls = [‘https://www.cnblogs.com/‘] urls_set = set() def parse(self, response): #獲取當前頁裏的所有頁碼的url對象列表 url_obj_list = Selector(response=response).xpath(‘//div[@class="pager"]/a/@href‘) ##或者2: starts-with(@屬性,‘值開頭‘) #url_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘) ##或者3:正則表達式固定用法re:test(@屬性值,"正則表達式") #url_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘) #將對象列表轉換成字符串列表 url_str_list = url_obj_list.extract() for url in url_str_list: #1.通過集合去除重復url if url not in self.urls_set: #print(url) self.urls_set.add(url) #拼接完整的url地址 full_url = self.start_urls[0] + url #將url頁碼傳給調度器去請求,並將下載的結果交給parse方法,yield的作用是將請求放入調度器 yield Request(url=full_url,callback=self.parse) for url in self.urls_set: print(url)代碼
在setting.py中結尾新增一行DEPTH_LIMIT=1來指定遞歸的層次,默認是0,所有層次
實例中關鍵點概括
@href #取屬性值 starts-with(@href,"xx") #屬性href的值以xx開始 re:test(@href,"/sitehome/p/\d+") #正則re:test固定搭配 yield Request(url=full_url,callback=self.parse) #交給調度器
六、item,pipeline使用
6.1 需求:將博客園的文章標題和url保存到一個文件a.txt文件裏。
各文件代碼如下:
# -*- coding: utf-8 -*- import scrapy from scrapy.selector import Selector from scrapy.http import Request from .. import items class Ip138Spider(scrapy.Spider): name = ‘ip138‘ allowed_domains = [‘www.cnblogs.com‘] start_urls = [‘https://www.cnblogs.com/‘] urls_set = set() def parse(self, response): #獲取當前頁面裏的標題和url==>返回字符串 title_str_list = Selector(response=response).xpath(‘//a[@class="titlelnk"]/text()‘).extract() href_str_list = Selector(response=response).xpath(‘//a[@class="titlelnk"]/@href‘).extract() for title_str,href_str in zip(title_str_list,href_str_list): #print(title_str,‘ ‘,href_str) #此處的參數title,和href來自於items.py文件裏類Cnblogs裏的屬性 item_obj = items.Cnblogs(title=title_str,href=href_str) #將item對象傳遞給pipelines yield item_obj #獲取當前頁裏的所有頁碼的url對象列表 page_obj_list = Selector(response=response).xpath(‘//div[@class="pager"]/a/@href‘) ##或者2: starts-with(@屬性,‘值開頭‘) #page_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘) ##或者3:正則表達式固定用法re:test(@屬性值,"正則表達式") #page_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘) #將對象列表轉換成字符串列表 page_str_list = page_obj_list.extract() for url in page_str_list: #1.通過集合去除重復url if url not in self.urls_set: self.urls_set.add(url) print(url) #拼接完整的url地址 full_url = self.start_urls[0] + url #將url頁碼傳給調度器去請求,並將下載的結果交給parse方法,yield的作用是將請求放入調度器 yield Request(url=full_url,callback=self.parse)ip138.py文件
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class Cnblogs(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() href = scrapy.Field()items.py文件
# -*- coding: utf-8 -*- # Define your item pipelines here # # Don‘t forget to add your pipeline to the ITEM_PIPELINES setting # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html class Day0310Pipeline(object): def process_item(self, item, spider): content = "%s %s\n"%(item[‘title‘],item[‘href‘]) f = open(‘a.json‘,‘a‘) f.write(content) f.close() # return itempipelines.py文件
ITEM_PIPELINES = { ‘day0310.pipelines.Day0310Pipeline‘: 300, }setting.py文件
6.2 實例中關鍵點概括
#items.py文件中 class Cnblogs(scrapy.Item): title = scrapy.Field() href = scrapy.Field() #ip138.py文件中 from .. import items item_obj = items.Cnblogs(title=title_str,href=href_str) #此處的參數title,和href來自於items.py文件裏類Cnblogs裏的屬性 yield item_obj #將item對象傳遞給pipelines #pipelines.py文件中,可對收集到的數據進行存儲 class Day0310Pipeline(object): def process_item(self, item, spider): #item為ip138.py文件裏的對象化的數據,spider為來自哪只蜘蛛對象 content = "%s %s\n"%(item[‘title‘],item[‘href‘]) f = open(‘a.json‘,‘a‘) f.write(content) f.close() #setting.py文件中註冊下pipelines的類 ITEM_PIPELINES = { ‘day0310.pipelines.Day0310Pipeline‘: 300, } 數字越高越優先
Scrapy爬蟲框架學習