馭蟲術-Python(不定時更新)
title: Python馭蟲術
tags: Python,爬蟲,小書匠
grammar_cjkRuby: true
---
配圖正在路上。
概念、工具 以及 協議
1.爬蟲
- 爬蟲就是 模擬瀏覽器傳送網路請求,獲取響應,按照規則提取資料的程式
爬蟲要的就是儲存資料,只抓取不儲存毫無用處
2.資料流向
- 呈現出來,用於網頁服務,或應用服務
進行儲存、資料分析
3.需要的軟體與環境
- 至少要有python環境
- Pycharm或者其他IDE
- chrome瀏覽:分析網頁原始碼
4.瀏覽器的請求
- url:可以進行解碼或轉碼
- 谷歌(瀏覽器)中的請求內容>Network
- 爬蟲和瀏覽器請求的URL地址有一定差別。elements與Network中的原始碼會不一樣。
5.HTTP與HTTPS
- Http:超文字傳輸協議:以明文方式進行傳輸,效率更高
- Https:Http+SSL(安全套接字層):傳輸資料之前,將資料加密,之後解密,效率較低,但是更安全
- HTTP協議:
- 請求:
- 請求行
- 請求頭:
- Status code:狀態碼
- Conection: keep-alive 支援長連線
- Cache-Control:max-age=0 快取控制為零
- User-Agent
- Upgrade-Insecure-Requests:支援將不安全請求轉換的功能
- Accept:表示我想接收什麼資料,q=權重
- Cookie:瀏覽器儲存在使用者本地的一些資訊,包括使用者密碼,賬號資訊,網站校驗資訊(例如csrf跨站保護)。會被攜帶傳送給伺服器。Cookie可以被伺服器用來判斷客戶端是否是爬蟲。
- Query-String-Parameters:請求資料(GET)
- From-data:請求資料(POST)
- 可以在Chorme中模擬多種版本的機器
- 請求體
- GET請求沒有請求體,資料放在URL中
- POST請求有請求體:攜帶資料,引數放置於請求體中,常用於登陸註冊、傳輸大文字。
- 響應:
- 響應頭
- set-Cookie:伺服器給本地設定的cookie資訊,伺服器通過該欄位設定cookie
- 響應體
- URL地址對應的響應
- 抓包:就是按一下F12,看一下瀏覽器傳送了什麼請求的資訊,這個過程就叫做抓包
requests模組
- requests模組是一個第三方包:用於處理資料請求,模擬http請求。
http請求的get請求方式
url = "http://www.baidu.com/"
response = requests.get(url=url)http請求的post請求方式
url = "http://www.baidu.com/"
data = {鍵:"值"}
response = requests.get(url=url,data=data)偽造(重塑)頭部資訊:
headers={"鍵":"值,}
response = requests.get(url=url,headers=headers)超時引數
配合異常捕獲,在指定時間返回響應
# 在三秒內必須返回響應,否則則會報錯
response = requests.get(url=url,headers=headers,timeout=3)response方法:
- response.text:獲取原始碼(易出現亂碼)
- response.encoding = response.apparent_encoding:設定伺服器的編碼為本地的編碼
response.content.decode():把相應的二進位制流,轉化成str型別
# 這裡的gbk 是 可選引數
response.content.decode("gbk")- response.request.url :請求的目標url地址
- response.url :響應的url地址,這個有時候會因為跳轉而和請求目標地址不一致
- response.request.headers 請求頭
response.headers 響應頭
- requests方式比urlib方式簡單
50%的動態內容:json格式的資料。
retring模組:
- 第三方模組,用於重試異常
用於重試出現異常的函式:通俗理解是,“出事了我都這,你儘管去做,做錯了也不怕,但最多三次”
from retrying import retry
# 作為裝飾器 裝飾函式,報錯仍然重複執行,直到三次才算出錯
@ retry(stop_max_attempt_number=3)
def fun1():
print("hello world.")
time.sleep(1)
raise ValueError("This is a test error.")
處理cookie相關的請求
- DEMO:人人網
- 直接攜帶cookie,然後請求URL
- 直接放在headers中
headers = {"Referver":"URL","User-Agent":"瀏覽器資訊","Cookie":"..."}
- cookie字典傳給cookie引數,這個辦法非常酷。Cookie引數只接收字典。【傳說中的字典推導式】
# Cookie字串 CookieStr = "anonymid=jm5lz4q0wv29sz; depovince=BJ; _r01_=1; JSESSIONID=abcpoYHrUXJZa6yQOiLxw; ick_login=4c5c0781-d37e-44c5-98a7-8e3fee81d222; ick=e74b83d4-c258-4de9-bd6c-3426f777fadd; XNESSESSIONID=949847ff1bf9; jebe_key=38dc9339-f175-472f-9288-02e4e7e4b59c%7Cd931901a60720bfd1a4f2f38c98639f3%7C1537147847212%7C1%7C1537147849534; wp_fold=0; jebecookies=054ec649-ffed-4989-beda-1be907785a33|||||; _de=BA25AEE63DF6B7A91E89E9A775AD2FBD; p=5929761e2707b622b09b23f92b3c04aa8; first_login_flag=1; ln_uact=15661592012; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; t=aaf1d9103cf916e1d824260c832ceaf38; societyguester=aaf1d9103cf916e1d824260c832ceaf38; id=968054908; xnsid=1acd462c; ver=7.0; loginfrom=null"
# 這是一個字典生成式,生成正式使用的Cookie Cookie = {i.split("=")[0]:i.split("=")[1] for i in CookieStr.split(";")} response = requests.get(url=url,headers=headers,cookies=Cookie)
- 通過session模組獲取cookie:(這應是最常用的方法)
- session = requests.session() 會話保持,例項session
- session.post(post_url,data,headers) 很多網頁的介面可以在表單的action提交地址中看到,但有一些需要抓包才能看到
- response = session.get(url,headers)
- 使用session不僅可以處理相關登陸,而且可以應對相關反爬措施。
- 處理登陸相關的驗證碼可以找:打碼兔
資料提取方法
JSON
- 資料交換格式,在Python的識別中其實是一個字串
- 學習處理和操縱json資料,非常重要
- 匯入標準庫模組json
import json
- json.loads(JSON資料) Json字串過載為Python可識別的字典(dict)型別
- 將Json字串轉化為Python容器型別(Dic,List)
Py_data = json.loads(response.text)`
- json.dumps(dict) 字典轉換成json字串
- 把Python資料格式轉化成字串
Js_data = json.dumps(Py_data)
- dumps引數;ensure_ascii=False 取消ASC編碼
Js_data = json.dumps(Py_data,ensure_ascii=False)
- dumps引數;indent=2 以首行縮排兩個空格 的形式列印或儲存,美化效果
Js_data = json.dumps(Py_data,indent=2)
- 瀏覽器的手機模式
- 抓包:
- 過濾:可以通過過濾URL來大幅提高抓包效率
- Preview:中文不會被編碼,會直接正常顯示
- API的獲取注意:動態資料無法正常顯示,很可能是Referer導致的
Xpath與lxml
Xpath是一種提取資料的語言
- 當使用Xpath-helper工具 定位到任何一個節點,該節點都會得到一個名為xh-highlight的class屬性做標識
- XPath-helper外掛
- 解析網頁內容:靜態內容(原始碼中有的)。
- ctrl+shift+x 撥出XPath-helper
- 按住shift移動游標,快速捕獲響應的xpath
- 1.選擇節點物件(標籤)
/html/head/meta
:能夠選中html下的head下的所有的meta標籤
- 2.從任意節點開始選擇
//li
:當前頁面所有的li標籤/html/head/link//li
:表示meta下的所有li標籤
- 3.定位到具體元素 [@]
//div[@class="father"]//li
: 獲取class名為father的div下的所有li標籤- 可以使用單引號
- 在頁面中,定位id往往比定位class更合適
- 4.獲取節點內文字 text()
//a/text()
:獲取a標籤中直接裸露的文字內容a//text()
:獲取a下的所有文字,包括子節點文字
- 5.選擇節點屬性內容
a/@href
:獲取a標籤中 href屬性中的內容xpath方法
- string()函式 提取多個子節點中的文字
# 獲取詞語解釋
w_ex = html2.xpath('//*[@id="content"]/div[2]')[0].xpath("string(.)")
lxml模組
- 第三方模組,解析xml內容
- etree.HTML方法,將響應的程式碼格式化,解析成標準的html格式。
@後面跟屬性,如果放在方括號中,代表對所過濾的標籤集合進行過濾。如果放在url後,則代表獲取該屬性的值
etree.HTML(response.text)
相對路徑與絕對路徑
- /是絕對路徑,絕對路徑的查詢難度比較大,比較麻煩
- //是相對路徑,一般情況下我們都使用相對路徑進行查詢
mango資料庫或資料夾
- 儲存爬取內容
- 在xpath中的下標切片,不支援負索引,而且是從一開始,而不是從零開始的。
- 把tbody去掉就好用了
JSON-View外掛
- 更便於檢視JSON資料,在原來的基礎上,優化了JSON資料的顯示格式
response
- text方法,響應的原始碼,字串型別;可以提取漢字。
encoding編碼
# 將響應資訊編碼改為網站制定編碼
response.encoding = response.apparent_encoding
檔案操作
- os模組,用於作業系統檔案
判斷資料夾是否存在
dir = "directory"
if not os.path.exsits(dir):
pass建立資料夾
dir = "directory"
os.mkdir(dir)開啟檔案與檔案讀寫
with("file_name","w+",encoding="utf-8") as f:
f.write(content)
爬取動態內容與基礎反爬
- 網頁是響應式載入,而不是一次性全部自動載入的
- Grome瀏覽器F12:
- Network中可以檢視請求資訊
- Network-XHR 檢視動態請求資訊
user-agent/eɪdʒənt/:顯示請求瀏覽器的核心
# 獲取返回響應資訊頭部,這個不是很重要
for v,j in response.headers.items():
print(v,':',j)
# 獲取請求資訊頭部
for v,j response.request.headers.items():
print(v,':',j)偽造請求資訊瀏覽器核心
headers = {
'User-Agent':'偽造的瀏覽器核心資訊'
}
response = requests.get(url=url,headers=headers)Referer溯源偽造
headers = {
有些網址的反爬策略是:某些網址的特定網頁會識別客戶端的refer資訊,這些資訊包含了客戶端的請求記錄。它的具體意思是,你必須經由訪問了我的主頁,跳轉到我的子頁面,而不是從URL直接過來。你先開我家門,才能到我的臥室,而不是從窗戶進來。否則就認為你是不合法的。
'Referer':'偽造的 上一級URL'
}
response = requests.get(url=url,headers=headers)- 在XHR中可以找到動態資料,以及動態資料的請求介面。
將json資料格式,格式化
py_date = json.loads(response.text())
IP代理 requests.proxies
相關則是隨機數模組 random
# 代理IP列表
proxies = [{"http":“133.12.45.12:8564”},{"協議":"IP:埠號"}]
# random隨機選擇列表中的一個元素生成代理
proxy = random。choice(proxies)
response = requests.get(proxies=proxy)
MongoDB 資料庫
- 基於分散式資料庫,非關係性資料庫中最接近關係型資料庫。
- 庫→集合→文件
伺服器端開啟服務
mongod.exe --dbpath C:\data\db(路徑)
指定服務地址開啟客戶端
mongod(在環境變數下)建立資料庫
use DB_NAME插入資料(建立集合)
db.tb_name.insert({key:value})檢視資料庫
show dbs;刪除資料庫
db.dropDatabase()建立集合
db.createCollection("set_name")檢視集合
show collections刪除集合
db.collection.drop()
建立代理
建立代理
proxies = [{"http":"113.122.8.45:53128"},{"http":"114.122.8.45:53128"},{"http":"115.122.8.45:53128"}]匯入隨機數模組
proxy = random.choice(proxies)
Retrying 模組
- pip install retrying (安裝)
- timeout=5 超時引數
Scrapy框架
- 建立爬蟲的命令方式
scrapy genspider x www.x.com
`# 這裡使用的版本是1.0以上的版本,在填寫爬蟲域名的時候 不需要加引號 - 執行爬蟲
scrapy crawl x
- 擴充套件:
- 檢視爬蟲專案的模式列表
>>>scrapy genspider -l Available templates: basic crawl csvfeed xmlfeed
- 使用上述模式中的一種,指定它,使用它進行開發(構建)爬蟲檔案。
spider.py檔案:
爬蟲檔案是整個框架中我們最常編寫的,裡面包括一些內容需要我們學習。
extract()函式
- 代替etree將格式化後的原始碼內容輸出
parse()函式
- parse() 是spider的一個方法。
- 被呼叫時,每個初始URL完成下載後生成的 Response 物件將會作為唯一的引數傳遞給該函式。
- 該方法負責解析返回的資料(response data),提取資料(生成item)以及生成需要進一步處理的URL的 Request 物件。
setting.py檔案:
這裡的配置有很多,但並不是我們所學的全部,譬如分散式設定,是要自己手寫進去的
- robots.txt的規則遵循設定:這裡設定是否遵循robots檔案的協定,一般情況下設定成False就行
# Obey robots.txt rules
ROBOTSTXT_OBEY = False # default:True
- 設定全域性Header頭:在settings.py檔案中搜索就可以找到,取消註釋之後可以將headers頭資訊加入進去。(在DownloadMiddlewares【下載中介軟體】中也可以加headers請求頭資訊,cookie,代理等。)
# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
- 設定爬取間隔:在制定範圍內隨機的秒數作為爬取間隔,下面這個五表示的是最大爬取間隔時間(框架會從中1~5秒中選取一個時間點),並不是每次爬取都使用這個數字作為間隔秒數。
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
- 開啟入庫入口檔案piplines.py的使用:在setting.py中可以找到這些程式碼,將它解開,就可以使用。同時還可以在ITEM_PIPELINES字典中設定新的內容(這些內容就是piplines.py中新的類),並且給它設定不同的優先順序。指數越低,優先順序越高。
#ITEM_PIPELINES = {
# 'Csdnboke.pipelines.CsdnbokePipeline': 300,
#}
piplines.py檔案:
一種去重方法
- 首先建立一個新的,使用邏輯實現去重,原始碼如下:
# 匯入模組
from scrapy.exceptions import DropItem
# 建立一個用於去重的類
class Set_it(object):
# 建立一個構造方法
def __init__(self):
self.set0 = set()
# 建立一個process_item方法,它會自動呼叫
def process_item(self, item, spider):
# 標題
title = item["title"]
# 判斷標題是否已經存入了set中
if title in self.set0:
# 將這條item記錄刪除,並且輸出一條提示資訊
raise DropItem("這一條內容已經存在了,所以我把它刪了:%s"%title)
# 否則將標題存入
else:
#
self.set0.add(title)
return item
newspaper(第三方爬蟲包)
newspaper是一個第三方包,用於快速抓取頁面資訊。它的開發團隊來自於美國,現在還仍在維護當中。如果要使用,首先要保證在你的電腦上下載並安裝這個包,對此,我們可以使用pip這樣的包管理器進行直接下載安裝,當然,用conda也可以。
- 安裝newspaper
pip install newspaper3k
- 在Python爬蟲檔案中匯入它
import newspaper
- 使用例項化一個newspaper的Article方法,這個方法接收兩個引數,第一個引數是Url,第二個引數是區域語言。
# 例項化Article
# demo:
# news = newspaper.Article()
news = newspaper.Article(url=base_url,language='zh')
- 執行Article的download方法儲存原始碼,然後執行parse方法,這兩步是目前必須的
news.download()
news.parse()
- 獲取頁面正文
content = news.text
- 獲取頁面標題
title = news.title
- 獲取文章內配圖
img = news.imges
【原始碼】我自己開發了一個轉字典為sql語句的指令碼
#coding=utf-8
'''非常厲害的包 v1.0
使用說明:首先要保證你的items中的鍵值與資料庫中的欄位吻合,其次要自己建立庫和資料表,
傳入你的item,並且傳入表的名稱
form:Asterism
'''
def sql(item,table):
'''
item: Your dict.
table: Your table name.
'''
# 生成兩個列表推導式
keylis = [key for key,values in item.items()]
vlis = [values for key,values in item.items()]
# 生成sql 語句中所需要的
str1215 = '"{}"'+',"{}"'*(len(item)-1)
str1217 = '{}'+',{}'*(len(item)-1)
str1216 = 'insert into '+table+'('+str1217+')'+' value ('+str1215+')'
_sql = str1216.format(*keylis,*vlis)
return _sql # 返回sql語句