基本配置與命令
1.安裝
win系統下有5個步驟
pip3 install wheel twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted pip3 install Twisted 17.1.0 cp35 cp35m win_amd64.wheel pip install pywin32 pip install scrapy
2.創建
scrapy startproject 項目名
- 創建普通爬蟲文件
cd 項目名 (進入項目目錄之后再創建爬蟲文件)
scrapy genspider 爬蟲文件名 www.xxx.com
- 創建crawlspider的爬蟲文件
scrapy genspider -t crawl 爬蟲文件名 www.xxx.com
- 一般注釋掉 allowed_domains = ['www.xxx.com']
3.配置項目
ROBOTSTXT_OBEY = False 不遵守機器人規則 USER_AGENT = '' 配置UA LOG_LEVEL = 'ERROR' 配置日志級別
中間件配置,管道配置時將注釋取消即可
4.執行項目
scrapy crawl 爬蟲文件名 scrapy crawl 爬蟲文件名 --nolog 不顯示日志運行 scrapy crawl 爬蟲文件名 -o 文件名.csv/json 保存結果到文件
應用
1.持久化本地存儲
1.使用命令,保存的本地文件格式限制為 (json csv xml jl jsonlines marshal pickle)
scrapy crawl 爬蟲文件名 -o 本地文件名.csv
2.使用管道
- 在settings.py中開啟管道!!!
- items.py文件中添加字段,如 name = scrapy.Field()
- 注意在爬蟲文件中要yield item 管道類中才能接受到item
- 在piplines.py文件中的管道類中的process_item函數中處理
- 爬蟲類
-
-
-
- open_spider()
- close_spider()
- process_item()
-
-
2.爬取全部網站的數據
手動請求發送,在爬蟲文件中的parse中,(callback是回調另一個parse解析函數)
yield scrapy.Request(url,callback)
3.進行post請求發送
spider類中重寫start_requests(self)方法,yield scrapy.FormRequest(url,parse,formdata)
def start_requestS(self): for url in self.start_urls: data = { 'kw':'cat'} yield scrapy.FormRequest(url=url,callback=self.parse,formdata=data)
4.處理cookie
- scrapy默認情況下自動處理cookie,在settings.py中配置
COOKIES_ENABLED = False
5.請求傳參
- 使用場景:如果使用scrapy爬取的數據沒有在同一張頁面中,則必須使用請求傳參
- 編碼流程:
- 需求:爬取的是 首頁中電影的名稱和 詳情頁中電影的簡介(全站數據爬取)
- 基於起始url進行數據解析(parse)
- 解析數據
-
-
- 電影的名稱
- 詳情頁的url
- 對詳情頁的url發起手動請求(指定的回調函數parse_detail),進行請求傳參(meta)meta傳遞給parse_detail這個回調函數
-
- 封裝一個其他頁碼對應url的一個通用的URL模板
- 在for循環外部,手動對其他頁的url進行手動請求發送(需要指定回調函數==》parse)
- 定義parse_detail回調方法,在其內部對電影的簡介進行解析。解析完畢后,需要將解析到的電影名稱和電影的簡介封裝到同一個item中。
- 接收傳遞過來的item,並且將解析到的數據存儲到item中,將item提交給管道
def parse_news(self,response): item = WangyiproItem() item['title'] = title yield scrapy.Request(url=news_detail_url,callback=self.parse_detail,meta={'item':item}) def parse_detail(self,response): item = response.meta['item'] item['content'] = content yield item
5.中間件
- 在settings中要取消注釋才能生效
- DOWNLOADER_MIDDLEWARES 下載中間件: 批量攔截所有的請求和響應
- process_request 攔截請求
-
- 用來進行UA偽裝,結合UA列表使用
- 使用代理ip,結合ip池使用
- process_response 攔截相應
可以在爬取動態加載的頁面時結合selenium使用

from scrapy import signals import random #批量攔截所有的請求和響應 class MiddlewearproDownloaderMiddleware(object): #UA池 user_agent_list = [ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 " "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24" ] #代理池 PROXY_http = [ '153.180.102.104:80', '195.208.131.189:56055', ] PROXY_https = [ '120.83.49.90:9000', '95.189.112.214:35508', ] #攔截正常請求:request就是該方法攔截到的請求,spider就是爬蟲類實例化的一個對象 def process_request(self, request, spider): print('this is process_request!!!') #UA偽裝 request.headers['User-Agent'] = random.choice(self.user_agent_list) return None #攔截所有的響應 def process_response(self, request, response, spider): return response #攔截發生異常的請求對象 def process_exception(self, request, exception, spider): print('this is process_exception!!!!') #代理ip的設定 if request.url.split(':')[0] == 'http': request.meta['proxy'] = random.choice(self.PROXY_http) else: request.meta['proxy'] = random.choice(self.PROXY_https) #將修正后的請求對象重新進行請求發送 return request
6.scrapy中使用selenium
1.spider類中定義一個屬性 (類屬性)
browser = Chrome(executable_path='chromedriver.exe')
2.spider類中重寫一個方法closed, 在該方法中關閉browser
def closed(self,spider): self.browser.quit()
3.在中間件類的process_response中編寫selenium自動化的相關操作

class DownloaderMiddleware(object): #攔截整個工程中所有的響應對象 def process_response(self, request, response, spider): if request.url in spider.urls: #獲取了在爬蟲類中定義好的瀏覽器對象 bro = spider.bro bro.get(request.url) bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') sleep(1) #獲取攜帶了新聞數據的頁面源碼數據 page_text = bro.page_source #實例化一個新的響應對象 new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request) return new_response else: return response
7.CrawlSpider 自動爬取全站的數據
- 作用:就是用於進行全站數據的爬取
- 新建一個CrawlSpider類的爬蟲文件
scrapy genspider -t crawl xxx www.xxx.com
- LinkExtractor 連接提取器:根據指定規則(正則表達式)進行連接的提取
- Rule規則解析器:
將鏈接提取器提取到的鏈接進行請求發送,然后對獲取的頁面數據進行指定規則的解析(callback)
一個連接提取器對應唯一一個規則解析器
- 示例 使用CrawlSpider爬取陽光問政王標題及詳情頁內容

# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from sunLinePro.items import SunlineproItem,ContentItem class SunSpider(CrawlSpider): name = 'sun' # allowed_domains = ['www.xxx.com'] start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page='] link= LinkExtractor(allow=r'type=4&page=\d+')#提取頁碼連接 link1 = LinkExtractor(allow=r'question/2019\d+/\d+\.shtml')#提取詳情頁的鏈接 rules = ( Rule(link, callback='parse_item', follow=False), Rule(link1, callback='parse_detail'), ) #解析出標題和網友名稱 def parse_item(self, response): tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr') for tr in tr_list: title = tr.xpath('./td[2]/a[2]/text()').extract_first() netFriend = tr.xpath('./td[4]/text()').extract_first() item = SunlineproItem() item['title'] = title item['netFriend'] = netFriend yield item #解析出新聞的內容 def parse_detail(self,response): content = response.xpath('/html/body/div[9]/table[2]//tr[1]/td/div[2]//text()').extract() content = ''.join(content) item = ContentItem() item['content'] = content yield item
scrapy分布式爬蟲
1.概念:
可以將一組程序執行在多台機器上(分布式機群),使其進行數據的分布爬取。
2.原生的scrapy框架是否可以實現分布式?不可以.
- 調度器不可以被分布式機群共享
- 管道不可以被分布式機群共享
3.借助scrapy-redis這個模塊幫助scrapy實現分布式
- scrapy-redis作用:
- 可以提供可以被共享的管道和調度器
4.使用scrapy-redis:
1.安裝scrapy-redis:
pip install scrapy-redis
2.爬蟲文件中:
- spider對應的分布式類
from scrapy_redis.spiders import RedisSpider
- Crawlspider對應的分布式類
from scrapy_redis.spiders import RedisCrawlSpider
3.修改爬蟲文件的代碼:
- 將當前爬蟲類的父類從CrawlSpider修改成RedisCrawlSpider
- 將start_urls刪除
- 添加一個新的類屬性redis_key = 'ts' (可以被共享的調度器中的隊列名稱)
4.設置管道piplines.py
ITEM_PIPELINES = {
'scrapy_redis_ep.pipelines.RedisPipeline': 400
# 'scrapyRedisPro.pipelines.ScrapyredisproPipeline': 300, }
5.settings.py中設置調度器
# 使用scrapy-redis組件的去重隊列,增加了一個去重容器類的配置, 作用使用Redis的set集合來存儲請求的指紋數據, 從而實現請求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis組件的調度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 是否暫停,配置調度器是否要持久化, 也就是當爬蟲結束了, 要不要清空Redis中請求隊列和去重指紋的set。如果是True, 就表示要持久化存儲, 就不清空數據, 否則清空數據 SCHEDULER_PERSIST = True
6.settings.py中設置redis服務器
REDIS_HOST = '192.168.12.154' REDIS_PORT = 6379 # REDIS_ENCODING = 'utf-8' # REDIS_PARAMS = {'password':'123456'}
7.配置redis:
修改Redis的配置文件:redis.windows.conf
- #bind 127.0.0.1 - protected-mode no
8.啟動redis
攜帶配置文件啟動redis服務
redis-server ./redis.windows.conf
啟動redis客戶端
redis-cli
執行工程
scrapy runspider xxx.py
手動將起始url扔入調度器的隊列中,在redis客戶端中輸入命令(redis-cli), xxx.com為起始url
lpush ts www.xxx.com
查看爬取的所有items
lrange 爬蟲文件名:items 0 -1
增量式爬蟲
增量式爬蟲
- 概念:監測網上數據更新的情況
比如爬取電影網時,過一段時間又會有新的電影產生,這是就不能再將所有數據存儲到數據庫中了因為會重復
- 數據指紋
將爬取的數據進行hash等方式轉換為一個不重復的值,存到數據庫中.
比如爬取糗百時,將爬到的標題和段子內容原始數據第一步先持久化存儲,第二步再將標題和內容拼接成一個字符串再進行hash生成一個data_id存入數據庫, 在下一次爬取時就可以將標題和內容拼接生成hash值(data_id),在數據庫中查詢是否存在這個id值,進而判斷數據是否存在

import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from redis import Redis from moviePro.items import MovieproItem class MovieSpider(CrawlSpider): name = 'movie' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.4567tv.tv/frim/index1.html'] link = LinkExtractor(allow=r'/frim/index1-\d+.html') rules = ( Rule(link, callback='parse_item', follow=False), ) conn = Redis(host='127.0.0.1',port=6379) #解析電影的名稱和詳情頁的url def parse_item(self, response): li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li') for li in li_list: title = li.xpath('./div/a/@title').extract_first() detail_url = 'https://www.4567tv.tv'+li.xpath('./div/a/@href').extract_first() item = MovieproItem() item['title'] = title #判斷該詳情頁的url是否進行請求發送 ex = self.conn.sadd('movie_detail_urls',detail_url) if ex == 1:#說明detail_url不存在於redis的set中 print('已有最新數據更新,請爬......') yield scrapy.Request(url=detail_url,callback=self.parse_detail,meta={'item':item}) else: print('暫無新數據的更新!!!') def parse_detail(self,response): item = response.meta['item'] desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first() item['desc'] = desc yield item
管道文件:

class MovieproPipeline(object): def process_item(self, item, spider): dic = { 'title':item['title'], 'desc':item['desc'] } conn = spider.conn conn.lpush('movie_data',dic) return item