1. 程式人生 > 實用技巧 >Flask工程配置載入方式

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對登陸按鈕的請求進行傳送
      (能夠爬取到登入成功之後的相關頁面資料)
  • 為什麼要模擬登陸

    • 有的頁面必須登陸之後才顯示
      驗證碼的識別
  • 線上的打碼平臺:超級鷹,雲打碼,打碼兔......

  • 超級鷹:http://www.chaojiying.com/

  • 超級鷹的使用流程

    • 註冊:使用者中心身份的賬戶
    • 登陸:
      • 檢視提分的剩餘
      • 建立一個軟體ID:軟體ID-》生成一個軟體ID(ID的名稱和說明)
      • 下載示例程式碼:開發文件-》選擇語言-》點選下載

例:使用超級鷹識別驗證碼圖片

先匯入它裡邊的 類方法(要是用pycharm,就把他封裝到一個py檔案裡)執行


例:模擬登陸

爬蟲中的非同步操作

  • 執行緒池(適當)
  • 單執行緒+多工非同步協程(推薦)
    • 協程:coroutine
    • 任務物件:stask
    • 事件迴圈物件:event_loop

多工非同步協程(併發):提升爬去效率

  • 協程:物件 coroutine。如果一個函式在定義的時候被async修飾了,則該函式被呼叫的時候會返回一個協程物件 ,函式內部的程式語句不會其呼叫的時候被執行(特殊的函式)

  • 任務物件:物件,就是對協程的進一步封裝。任務物件協程特殊的函式.任務物件中可以顯示
    協程的相關狀態。任務物件可以被繫結一個回撥。
    - 繫結回撥:

  • 事件迴圈:無限(不確定迴圈次數)的迴圈。需要向其內部註冊多個任務物件(特殊的函式)。

  • async:專門用來修飾函式

  • await:掛起

單執行緒+多工非同步協成
asyncio模組:協成
aiohttp模組:非同步協成




基於非同步的操作

協成操作

Aiohttp模組實現多工非同步爬蟲


selenium模組

Pyppeteer(支援非同步) ==selenium(不支援)
Pyppeteer通用性和適用性不強

概念

模組。基於瀏覽器自動化的模組。


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)
      負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的資訊。當頁面被爬蟲解析後,將被髮送到專案管道,並經過幾個特定的次序處理資料。

使用場景:

爬取的資料不在同一張頁面中
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)