Flask工程配置載入方式
資料分析三劍客:
概念:是把隱藏在一些看似雜亂無章的資料背後的資訊提煉出來,總結出所研究物件的內在規律
Numpy 支援大量的維度陣列與矩陣運算,
Pandas 處理資料丟失,
Matplotlib 是回值曲線圖的,
**requests模組 **
text字串形式的響應資料
json
content 二進位制流
proxy="{http:ip:port}
aiohttp模組
text()字串形式的響應資料
json()
read()二進位制型別的資料
requests模組
Response.text:返回的是字串形式的響應資料 Response.json(): 返回json資料 Response.content:返回的是二進位制流(圖片,mp3)
urllib的用法
url = 'http://img2.imgtn.bdimg.com/it/u=1718395925,3485808025&fm=26&gp=0.jpg'
urllib.request.urlretrieve(url=url,filename='./123.png')
爬取sogo的頁面
url = 'https://www.sogo.com/' response = requests.get(url=url) #.text返回的是字串形式的響應資料 page_text=response.text with open('./sogou.html','w',encoding='utf-8') as fp: fp.write(page_text)
攜帶動態的 引數
url = 'https://www.sogou.com/web?query=jay' #動態的 引數 wd = input('enter a word:') param = { 'query':wd } headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36' } #攜帶了動態的引數進行的請求傳送 response = requests.get(url=url,params=param,headers=headers) #手動修改響應資料 的編碼 response.encoding='utf-8' page_text = response.text filename = wd+".html" with open(filename,'w',encoding='utf-8') as fp: fp.write(page_text) print(filename,'下載成功')
**爬取豆瓣電影中電影的詳情資料 **
url = 'https://movie.douban.com/j/chart/top_list'
s = input('enter a start:')
l = input('enter a limit:')
header = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'
}
param = {
"type": "24",
"interval_id": "100:90",
"action":"" ,
"start": s,
"limit":l,
}
response = requests.get(url=url,headers=header,params=param)
page_text = response.text
print(type(page_text))
爬取圖片
url='http://img2.imgtn.bdimg.com/it/u=1718395925,3485808025&fm=26&gp=0.jpg'
header = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'
}
img_data = requests.get(url=url,headers=header).content
with open('./fj.jpg','wb') as f:
f.write(img_data)
爬取糗事百科中的糗圖資料
re.S:單行處理,可以處理換行
import re
import os
import requests
from urllib import request
if not os.path.exists('./qiutuLibs'):
os.mkdir('./qiutuLibs') #建立檔案呀
#通用的url模板(不可變)
url = 'https://www.qiushibaike.com/pic/page/%d/?s=5205107'
header = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"
}
for page in range(1,36):
new_url = format(url%page)
page_text = requests.get(url=new_url,headers = header).text
#資料解析,img的屬性值(圖片的連線)
ex = '<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
img_src_list = re.findall(ex,page_text,re.S)
for src in img_src_list:
src = 'https:'+src
img_name = src.split('/')[-1]
img_path = './qiutuLibs/'+img_name
request.urlretrieve(src,img_path)
print(img_name+'下載成功')
第一個反爬機制
robots協議,
特性:防君子不防小人
https和http相關
- http協議:客戶端和伺服器 端進行資料互動的形式。
- 常用的請求頭資訊
- User-Agent:請求載體的身份標識
- Connection:close
- 響應頭資訊
- content-type
- 常用的請求頭資訊
- https:安全的http(加密)
- 對稱祕鑰加密:客戶端 - 加密資訊 - 伺服器(把祕鑰很密文同時傳送,存在隱患)
- 非對稱祕鑰加密:服務端把公鑰給客戶端,客戶端加密後把密文發回服務端(客戶端不能保證公鑰是哪個指定伺服器發的)
- 證書祕鑰加密(***):證書":公開祕鑰,服務端會產生公開金鑰,把祕鑰交給證書認證機構,做數字簽名,把證書交給客戶端,客戶端通過公鑰給密文加密,然後把密文交給服務端
UA檢測
網站會檢測當前請求的請求載體的身份標識。
如何破解(uA偽裝)
將user-agent對應得資料封裝到字典中,將字典作用到請求方法的headers引數中
什麼是動態加在資料?
通過ajax或js請求到的資料
如何獲取動態載入資料?
在抓包工具中進行全域性搜尋, 定位到動態載入資料對應的資料包,從資料包提取url和引數
Get和post方法中常用的引數
url headers params/data
一、什麼是爬蟲?
通過編寫程式讓其模擬瀏覽器上網,然後去網際網路中抓取資料的過程\n",
爬蟲的分類
通用爬蟲:就是抓取一整張頁面原始碼內容
聚焦爬蟲:抓取的是頁面中區域性的內容
增量式爬蟲:可以監測網站資料更新的情況。抓取網站中最新更新出來的資料
反爬機制 :對應的載體數網站。
反反爬策略: 對應的載體爬蟲程式.
探究一下爬蟲的合法性:
爬蟲本身是不被法律禁止(中立性)
爬取資料的違法風險的體現:
爬蟲干擾了被訪問網站的正常運營
爬蟲抓取了受到法律保護的特定型別的資料或資訊
如何規避違法的風險?
嚴格遵守網站設定的robots協議;
在規避反爬蟲措施的同時,需要優化自己的程式碼,避免干擾被訪問網站的正常執行;
在使用、傳播抓取到的資訊時,應審查所抓取的內容,如發現屬於使用者的個人資訊、隱私或者他人的商業祕密的,應及時停止並刪除。
二、資料解析方式
實現資料解析方式
正則,bs4,xpath,pyquery
為什麼使用資料解析?
資料解析是實現聚焦爬蟲的核心技術,就是在一張頁面原始碼中提取除指定的文字內容
通用解析原理?
要解析提取的資料都是儲存在標籤中間或者是標籤的屬性中
1)標籤定位
2)取文字或者取屬性
通用解決亂碼的處理方式
1) img_title = img_title.encode('iso-8859-1').decode('gbk')
2) response = requests.get(url=new_url,headers=header)
response.encoding = 'utf-8'
page_text = response.text
1.正則解析
re.S:單行處理,可以處理換行
2.bs4解析
解析原理:
1).例項化一個BeautifulSoup的一個物件,且將即將被解析的頁面原始碼載入到該物件中\n",
2).需要呼叫bs物件中相關屬性和方法進行標籤定位和資料的提取\n",
環境安裝
pip install lxml(解析器)\n",
pip install bs4\n",
BeautifulSoup物件的例項化
BeautifulSoup('fp','lxml'):將本地儲存的一張html頁面中的頁面原始碼載入到bs物件中
BeautifulSoup(page_text,'lxml'):將網際網路請求到的頁面原始碼資料載入到bs物件"
bs相關屬性和方法
tagName就是div a標籤
attrName是class id 屬性
soup.tagName #可以定位到第一次出現的tagName標籤,返回值是一個單數
find('tagName') == soup.tagName"
屬性定位
find('tagName',attrName='value'),返回的也是單數
find_all(): 和find的用法一樣,只是返回值是一個列表(複數)
select('選擇器'):id,class,標籤,層級選擇器,返回值為列表.
>表示一個層級 空格表示多個層級
取文字
string定位的是直系的文字內容
text,get_text()定位的是所有的文字內容
取屬性
tag['attrName']"
**使用bs 解析本地儲存的頁面中相關的區域性資料 **
from bs4 import BeautifulSoup
fp = open('./index.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
爬取詩詞名句網資料
把資料存在本地
import requests
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
header = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"
}
page_text = requests.get(url=url,headers=header).text
#資料解析 :章節標題和對應得內容
soup = BeautifulSoup(page_text,'lxml')
a_list = soup.select('.book-mulu > ul > li > a')
fp = open('./sanguo.txt','w',encoding='utf-8')
for a in a_list:
title = a.string
detail_url = 'http://www.shicimingju.com'+a['href']
# print(detail_url)
detail_page_text = requests.get(url=detail_url,headers=header).text
# print(detail_page_text)
#解析詳情頁的頁面原始碼
soup = BeautifulSoup(detail_page_text,'lxml')
content = soup.find('div',class_="chapter_content").text
# content = soup.select('.chapter_content')
# print(content)
fp.write(title+':'+content+'\n')
print(title,'下載成功')
fp.close()
Soup.a: 拿到a標籤
soup.find(‘div’,class_=’tang)
soup.select(‘.tang > a’)[1].string: 拿到的是a標籤的內容 1是下標索引
Soup.select(‘.tang > img’)[0][‘src’] :s索引為0的img標籤,取屬性src
.select(‘.tang > ul >li > a’)== .select(‘.tang a’)
3.xpath解析
- 優點:通用性強
- 解析原理:
- 1.例項化一個etree的物件,將即將被解析的頁面原始碼載入到該物件中\n",
- 2.呼叫etree物件中的xpath方法結合著不同的xpath表示式實現標籤定位和資料提取
- 環境安裝:
- pip install lxml
- etree物件例項化:
- etree.parse('filePath') #解析的是本地
- etree.HTML(page_text) #解析的是瀏覽器的
xpath 相關的屬性和方法
xpath方法返回值是列表
最左側如果為一個斜槓,則表示必須從跟節點開始進行標籤定位
最左側為兩個斜槓,表示可以從任意位置標籤定位
非最左側的一個斜槓表示一個層級,兩個斜槓表示多個層級
屬性定位
//tagName[@attrName='value']
索引定位
//div[@class=\"tang\"]/ul/li[2] 索引是從1開始
取文字
/text() //text()
取屬性
/@attrName
爬取boss(崗位名稱,公司名稱,薪資,崗位描述)
from lxml import etree
import requests
tree = etree.parse
url = 'https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&city=101010100&industry=&position='
header = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"
}
page_text = requests.get(url=url,headers=header).text
#解析
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="job-list"]/ul/li')
for li in li_list:
jog_name = li.xpath('./div/div[@class="info-primary"]/h3/a/div[1]/text()')[0]
salary = li.xpath('./div/div[@class="info-primary"]/h3/a/span/text()')[0]
company = li.xpath('.//div[@class="company-text"]/h3/a/text()')[0]
detail_url = 'https://www.zhipin.com'+li.xpath('./div/div[@class="info-primary"]/h3/a/@href')[0]
detail_page_text = requests.get(detail_url,headers=header).text
#解析詳情頁中的崗位描述
tree = etree.HTML(detail_page_text)
job_desc = tree.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div//text()')
job_desc = ''.join(job_desc)
print(jog_name,salary,company,job_desc)
好處:使用 | 管道符,使得xpath表示式更具有通用性(放到一個列表裡)
"tree.xpath('//div[@class=\"bottom\"]/ul/li/a/text() | //div[@class=\"bottom\"]/ul/div[2]/li/a/text()')"
**圖片懶載入概念:偽屬性 **
圖片懶載入是一種網頁優化技術。圖片作為一種網路資源,在被請求時也與普通靜態資源一樣,將佔用網路資源,而一次性將整個頁面的所有圖片載入完,將大大增加頁面的首屏載入時間。為了解決這種問題,通過前後端配合,使圖片僅在瀏覽器當前視窗內出現時才載入該圖片(真屬性),達到減少首屏圖片請求數的技術就被稱為“圖片懶載入
網站一般如何實現圖片懶載入技術呢?
在網頁原始碼中,在img標籤中首先會使用一個“偽屬性”(通常使用src2,original......)去存放真正的圖片連結而並非是直接存放在src屬性中。當圖片出現到頁面的視覺化區域中,會動態將偽屬性替換成src屬性,完成圖片的載入
HTTPConnectionPool(host:XX)Max retries exceeded with url
錯誤產生的原因
- 爬蟲在短時間內發起了高頻的網路請求,請求對應的ip就會被伺服器端禁
- 連線池資源被耗盡
處理方式:
- 在headers里加connection:“close”, 或是改IP
代理
- 代理:代理伺服器
- 基於代理的網站
- 站大爺
- goubanjia
- 快代理
- 西祠代理
- 代理的匿名度
- 透明:使用透明代理,對方伺服器可以知道你使用了代理,並且也知道你的真實IP\n",
- 匿名:對方伺服器可以知道你使用了代理,但不知道你的真實IP。\n",
- 高匿:對方伺服器不知道你使用了代理,更不知道你的真實IP\n",
- 型別
- http:代理伺服器只可以轉發http協議的請求\n",
- https:代理伺服器只可以轉發https協議的請求\n",
- 編碼:
- 在get或者post方法中應用一個proxies的引數,給其引數賦值為{'http':'ip:port'}
例
url = 'https://www.baidu.com/s?wd=ip'
page_text = requests.get(url,headers=header,proxies={'http':'113.108.242.36:47713'}).text
with open('./ip.html','w',encoding='utf-8') as f:
f.write(page_text)
動態請求引數:
出現在post請求引數中
通常情況下動態引數往往都被隱藏在了前臺頁面中
cookie處理
- 處理方式
- 手動處理:將cookie的鍵值對手動新增到headers字典中,然後將headers作用到get或者post方法的headers引數中
- 自動處理:使用Session。\n",
- session作用:session可以和requests一樣進行請求的傳送\n",
- 特性:使用session發起請求,如果請求過程中產生cookie,則cookie會被自動儲存到session中"
例 爬取雪球網
url = 'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=-1&count=10&category=-1'
# requests.get(url,headers=header).text
#建立一個session物件
session = requests.Session()
#獲取cookie
session.get('https://xueqiu.com/',headers=header)
#攜帶cookie進行的請求傳送
session.get(url,headers=header).json()
模擬登陸
-
什麼是模擬登陸
- 使用requests對登陸按鈕的請求進行傳送
(能夠爬取到登入成功之後的相關頁面資料)
- 使用requests對登陸按鈕的請求進行傳送
-
為什麼要模擬登陸
- 有的頁面必須登陸之後才顯示
驗證碼的識別
- 有的頁面必須登陸之後才顯示
-
線上的打碼平臺:超級鷹,雲打碼,打碼兔......
-
超級鷹的使用流程
- 註冊:使用者中心身份的賬戶
- 登陸:
- 檢視提分的剩餘
- 建立一個軟體ID:軟體ID-》生成一個軟體ID(ID的名稱和說明)
- 下載示例程式碼:開發文件-》選擇語言-》點選下載
例:使用超級鷹識別驗證碼圖片
先匯入它裡邊的 類方法(要是用pycharm,就把他封裝到一個py檔案裡)執行
例:模擬登陸
爬蟲中的非同步操作
- 執行緒池(適當)
- 單執行緒+多工非同步協程(推薦)
- 協程:coroutine
- 任務物件:stask
- 事件迴圈物件:event_loop
多工非同步協程(併發):提升爬去效率
-
協程:物件 coroutine。如果一個函式在定義的時候被async修飾了,則該函式被呼叫的時候會返回一個協程物件 ,函式內部的程式語句不會其呼叫的時候被執行(特殊的函式)
-
任務物件:物件,就是對協程的進一步封裝。任務物件協程特殊的函式.任務物件中可以顯示
協程的相關狀態。任務物件可以被繫結一個回撥。
- 繫結回撥: -
事件迴圈:無限(不確定迴圈次數)的迴圈。需要向其內部註冊多個任務物件(特殊的函式)。
-
async:專門用來修飾函式
-
await:掛起
單執行緒+多工非同步協成
asyncio模組:協成
aiohttp模組:非同步協成
基於非同步的操作
協成操作
Aiohttp模組實現多工非同步爬蟲
selenium模組
Pyppeteer(支援非同步) ==selenium(不支援)
Pyppeteer通用性和適用性不強
概念
模組。基於瀏覽器自動化的模組。
- 爬蟲之間的關聯
- 實現模擬登陸
- 非常便捷的獲取動態載入的頁面資料
- 環境的安裝:pip install selenium
- selenium的基本使用
- 例項化一個瀏覽器物件(必須將瀏覽器的驅動程式進行載入)
- 驅動程式下載:http://chromedriver.storage.googleapis.com/index.html
- 對映關係表:http://blog.csdn.net/huilan_same/article/details/51896672\n",
- 通過程式碼指定相關的行為動作
Js window.scrollTo(0,document.body.scrollHeight):滾條跳到尾
例
Selenium 如何規避網站監測
正常情況下我們用瀏覽器訪問淘寶等網站的 window.navigator.webdriver的值為
undefined。而使用selenium訪問則該值為true
Selenium 訪問值為true,就是被檢測了,
只需要設定Chromedriver的啟動引數即可,引數'excludeSwitches',他的值為['enable-automation']
iframe
分析發現定位的a標籤出現在iframe標籤之下,則必須通過switch_to.frame操作後,才可以進行標籤定位
phantomJs:是一個無視覺化介面的瀏覽器
例:谷歌瀏覽器
from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 例項化了一個谷歌瀏覽器物件且將驅動程式進行了載入\n",
bro = webdriver.Chrome(executable_path='./chromedriver.exe',chrome_options=chrome_options)
bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
bro.save_screenshot('./1.png') #截圖,看看無視覺化介面跑哪了
print(bro.page_source)
scrapy框架
抓包工具
fiddler mitmproxy, 青花瓷(傳送請求來提取資料的,相當於代理)
移動端資料爬取
- 抓包工具:
- fiddler,mitmproxy,青花瓷
- fiddlers相關配置
- 在手機中安裝抓包工具的證書
- 將手機網路和fidders所在的機器配置到同一網段中
- 在手機中訪問fidder伺服器的一張子頁面進行證書下載(信任和安裝)
- (手機)網路代理配置:
- 將手機進行代理設定
- 代理ip:fidders所在機器的ip
- 埠:fidder自己的埠
概念
就是一個具有很強通用性且已經集成了很多功能的專案模板
scrapy功能(不帶任何視覺化介面),效率優於pyspider
- 高效能的資料解析
- 高效能的持久化儲存
- 中介軟體
- 分散式
- 非同步的資料下載(基於twisted實現)
pyspider框架:有視覺化介面
環境安裝
linux
pip install scrapy
windows
a. pip3 install wheel
b. 下載twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
c. 進入下載目錄,執行 pip3 install
Twisted17.1.0cp35cp35mwin_amd64.whl
d. pip3 install pywin32
e. pip3 install scrapy
spider使用
- 建立一個工程:scrapy startproject ProName
- cd ProName
- 在爬蟲資料夾(spiders)中建立一個爬蟲檔案:scrapy genspider spiderName www.x.com
- 配置檔案:
- 進行UA偽裝
- 不遵從robots
- 日誌等級的指定 LOG_LEVEL = 'ERROR'
- 執行工程:scrapy crawl spiderName
持久化儲存
-
基於終端指令
- 使用:可以將parse方法的返回值儲存到本地磁碟檔案中
- 指令:scrapy crawl spiderName -o filePath
- 好處:便捷
- 弊端:侷限性強,只可以將資料儲存到指定字尾的文字檔案,只可以將資料儲存到檔案,不能存到資料庫中(字尾:'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle')
-
基於管道
- 編碼流程:
- 資料解析
- 在item類中進行相關屬性定義
- 將解析的資料封裝到item型別的物件中
- 將item物件提交給管道
- 管道接收item然後呼叫process_item方法進行資料的持久化儲存
- 將管道開啟
- 編碼流程:
使用
(1)配置setting
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
content = div.xpath('./a/div/span//text()').extract()
content = ''.join(content)
div.xpath(‘’) [0] #取得是<Selector >物件
extract_first() #取得是單數
extract()#取得是複數放在列表裡,通過
content = ''.join(content)拼接得到內容
(2)儲存到本地
基於管道
- 資料解析
- 在item類中進行相關屬性定義
-
將解析的資料封裝到item型別的物件中
from firstBlood.items import FirstbloodItem
def parse(self, response): # response就是<200 https://www.baidu.com/>
div_list = response.xpath('//*[@id="content-left"]/div')
# 觀察發現:解析出的字串資料都儲存在了Selector物件中
for div in div_list:
author = div.xpath(
'./div[1]/a[2]/h2/text()').extract_first() # [0]取得是
content = div.xpath('./a/div/span//text()').extract()
content = ''.join(content)
#例項化item物件
item = FirstbloodItem()
# 將解析的資料封裝到item中
item['author'] = author #將解析到的author儲存到item物件的author屬性中
item['content'] = content
# 將item提交給管道
yield item -
管道接收item然後呼叫process_item方法進行資料的持久存本地
對應的是一種資料儲存的方式
class FirstbloodPipeline(object):
# 保證檔案只打開一次
f = None
def open_spider(self,spider):
print('開始爬蟲')
self.f = open('qiubai.txt','w',encoding='utf-8')# item就是用來接收爬蟲檔案提交過來的item物件 # process_item每接收一個item就會被呼叫一次 def process_item(self, item, spider): print(item) self.f.write(item['author']+':'+item['content']+'\n') return item def close_spider(self,spider): print('結束爬蟲') self.f.close()
-
將管道開啟
300優先順序,數值越小優先順序越高
-
執行
2)存MySQL中 在pip2lines.py中寫
# 存在MySQL資料庫
class mysqlPileLine(object):
conn = None
cursor = None
def open_spider(self,spider):
self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='',db='spider',charset='utf8')
self.cursor = self.conn.cursor()
print(self.conn)
def process_item(self,item,spider):
sql = 'insert into qiubai values ("%s","%s")'%(item['author'],item['content'])
try:
self.cursor.execute(sql)
self.conn.commit()
except Exception as e:
print(e)
self.conn.rollback()
return item
def close_spider(self,spider):
self.cursor.close()
self.conn.close()
改配置
ITEM_PIPELINES = {
# 'firstBlood.pipelines.mysqlPileLine': 301,
- 在終端建庫,建表,檢視
3)存redis資料庫中
將redis的版本切換到2.10.6 pip install -U redis==2.10.6
class redisPileLiine(object):
conn = None
def open_spider(self,spider):
self.conn = Redis(host='127.0.0.1',port=6379)
def process_item(self,item,spider):
# 將redis的版本切換到2.10.6 pip install -U redis==2.10.6
dic = {
'author':item['author'],
'content':item['content']
}
self.conn.lpush('qiubai',dic)
改配置
ITEM_PIPELINES = {
'firstBlood.pipelines.redisPileLiine': 302,
啟動redis
keys *
llen qiubai :檢視長度
ImagesPileline類
在piplines.py
#定製指定父類的管道類
class ImgPileline(ImagesPipeline):
#根據圖片地址進行圖片資料的請求
def get_media_requests(self,item,info):
#不需要指定回撥函式
yield scrapy.Request(url=item['img_src'])
# 指定圖片儲存的名稱
def file_path(self,request,response=None,info=None):
url = request.url #圖片地址
name = url.split('/')[-1]
return name
#將item傳遞給下一個即將被執行的管道類
def item_completed(self,results,item,info):
return item
在setting裡
ITEM_PIPELINES = {
'imgPro.pipelines.ImgPileline': 300,
}
三、Scrapy五大核心元件
每一個元件的作用
- 元件之間的工作流程
- 引擎(Scrapy)
用來處理整個系統的資料流處理, 觸發事務(框架核心) - 排程器(Scheduler)
用來接受引擎發過來的請求, 壓入佇列中, 並在引擎再次請求的時候返回. 可以想像成一個URL(抓取網頁的網址或者說是連結)的優先佇列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址 - 下載器(Downloader)
用於下載網頁內容, 並將網頁內容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的非同步模型上的)
- 爬蟲(Spiders)
爬蟲是主要幹活的, 用於從特定的網頁中提取自己需要的資訊, 即所謂的實體(Item)。使用者也可以從中提取出連結,讓Scrapy繼續抓取下一個頁面
- 專案管道(Pipeline)
負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的資訊。當頁面被爬蟲解析後,將被髮送到專案管道,並經過幾個特定的次序處理資料。
- 引擎(Scrapy)
使用場景:
爬取的資料不在同一張頁面中
Request(url,callback,meta={xx:xx}):meta就可以傳遞個callback
callback接受meta:response.meta
例:
url = 'https://www.4567tv.tv/index.php/vod/show/class/%E5%8A%A8%E4%BD%9C/id/1/page/2.html'
page_num = 2
def detail_parse(self,response):
desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
item = response.meta['item']
item['desc'] = desc
yield item
def parse(self, response):
li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
for li in li_list:
name = li.xpath('./div/a/@title').extract_first()
detail_url = 'https://www.4567tv.tv'+li.xpath('./div/a/@href').extract_first()
item = MovieproItem()
item['name'] = name
# meta是一個字典,可以將meta傳遞給callback
yield scrapy.Request(detail_url,callback=self.detail_parse,meta={'item':item})
Scrapy的相關配置:
增加併發:
預設scrapy開啟的併發執行緒為32個,可以適當進行增加。在settings配置檔案中修改CONCURRENT_REQUESTS = 100值為100,併發設定成了為100。
降低日誌級別:
在執行scrapy時,會有大量日誌資訊的輸出,為了減少CPU的使用率。可以設定log輸出資訊為INFO或者ERROR即可。在配置檔案中編寫:LOG_LEVEL = ‘INFO’
禁止cookie:
如果不是真的需要cookie,則在scrapy爬取資料時可以禁止cookie從而減少CPU的使用率,提升爬取效率。在配置檔案中編寫:COOKIES_ENABLED = False
禁止重試:
對失敗的HTTP進行重新請求(重試)會減慢爬取速度,因此可以禁止重試。在配置檔案中編寫:RETRY_ENABLED = False
減少下載超時:
如果對一個非常慢的連結進行爬取,減少下載超時可以能讓卡住的連結快速被放棄,從而提升效率。在配置檔案中進行編寫:DOWNLOAD_TIMEOUT = 10 超時時間為10s
整理:
資料解析:response.xpath()
-
scrapy的xpath和etree的xpath的區別:
- xpath返回的列表元素的型別不一樣
- extract() extract_first()
-
細節處理:
- 什麼時候需要編寫多個管道類
- 場景:爬取到的資料一份存入本地檔案,一份儲存mysql,redis
-
管道檔案中管道類表示什麼含義?
- 一個管道類對應一種持久化儲存的方式
- process_item中返回值的作用:
- return item:將item傳遞給下一個即將被執行的管道類
- 基於Spider父類的全站資料爬取
- 手動請求傳送
- yield scrapy.Request(url,callback):callback指定解析方法 (get)
- 手動請求傳送
yield scrapy.Request(url=new_url,callback=self.parse) #get請求
- yield scrapy.FormRequest(url,callback,formdata)#post請求 - 對起始url列表發起post請求: def start_requests(self): for url in self.start_urls: yield scrapy.FormRequest(url,formdata={},callback=self.parse) - 注意:scrapy如果發起post請求,scrapy會自動處理cookie
反爬蟲機制
3.1 使用代理
適用情況:限制IP地址情況,也可解決由於“頻繁點選”而需要輸入驗證碼登陸的情況。
這種情況最好的辦法就是維護一個代理IP池,網上有很多免費的代理IP,良莠不齊,可以通過篩選找到能用的。對於“頻繁點選”的情況,我們還可以通過限制爬蟲訪問網站的頻率來避免被網站禁掉。
proxies = {'http':'http://XX.XX.XX.XX:XXXX'}
Requests:
import requests
response = requests.get(url=url, proxies=proxies)
Urllib2:
import urllib2
proxy_support = urllib2.ProxyHandler(proxies)
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
urllib2.install_opener(opener) # 安裝opener,此後呼叫urlopen()時都會使用安裝過的opener物件
response = urllib2.urlopen(url)
3.2 時間設定
適用情況:限制頻率情況。
Requests,Urllib2都可以使用time庫的sleep()函式
import time
time.sleep(1)
3.3 偽裝成瀏覽器,或者反“反盜鏈”
有些網站會檢查你是不是真的瀏覽器訪問,還是機器自動訪問的。這種情況,加上User-Agent,表明你是瀏覽器訪問即可。有時還會檢查是否帶Referer資訊還會檢查你的Referer是否合法,一般再加上Referer。
headers = {'User-Agent':'XXXXX'} # 偽裝成瀏覽器訪問,適用於拒絕爬蟲的網站
headers = {'Referer':'XXXXX'}
headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}
Requests:
response = requests.get(url=url, headers=headers)
Urllib2:
import urllib, urllib2
req = urllib2.Request(url=url, headers=headers)
response = urllib2.urlopen(req)