青魔法-馭蟲術(不定時更新)

青魔法Python-馭蟲術

本文做者:魏泯html

博客源地址:https://www.cnblogs.com/simple/python

作有效率的魔法師sql

*跳轉到文章結尾*mongodb


目錄

  • 概念、工具以及協議
  • 使用requests模塊開發爬蟲程序
    • rquests請求
    • requests的其餘參數
    • response響應對象
  • 處理cookie相關的請求
  • Scrapy框架
  • 第三方模塊
  • 微型ORM(對象關係映射)腳本【源代碼】

概念、工具 以及 協議

爬蟲

爬蟲就是 模擬瀏覽器發送網絡請求,獲取響應,按照規則提取數據的程序。爬蟲要的就是保存數據,只抓取不保存毫無用處。chrome

數據流向

  • 呈現出來,用於網頁服務,或應用服務
  • 進行保存、數據分析

須要的軟件與環境

  • python環境
  • Pycharm
  • chrome瀏覽器

瀏覽器的請求

Url:須要進行解碼或轉碼
爬蟲和瀏覽器請求的URL地址有必定差異。Elements與Network中的源碼會不同。數據庫

HTTP與HTTPS

Http:超文本傳輸協議:以明文方式進行傳輸,效率更高。
Https:Http+SSL(安全套接字層):傳輸數據以前,將數據加密,以後解密,效率較低,可是更安全。json

這二者都包含請求與響應部分。瀏覽器

請求

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,在Network中查看瀏覽器發送了什麼請求的信息,這個過程就叫作抓包

*返回目錄再看看*


使用requests模塊開發爬蟲程序

requests的方法

requests模塊是一個第三方包:用於模擬http數據請求。
在接下來的內容裏咱們學習一下它的多種請求。
requests方式比urlib方式簡單
50%的動態內容是json格式的數據。

requests模塊的請求方法

  • requests請求的get請求方式

Http請求的get的請求方式:

使用這種方式獲得一個響應對象

url = "http://www.baidu.com/"
response = requests.get(url=url)

Terminal:

<Response [200]>
  • requests請求的post請求方式

使用這種方式獲得一個響應對象

url = "http://www.baidu.com/"
data = {鍵:"值"}
response = requests.get(url=url,data=data)

Terminal:

<Response [200]>

請求頭部信息:

  • 僞造/重塑 請求頭部信息:

headers是一個Hash字典,以鍵值的方式存放頭部信息。
例如:

headers={"鍵":"值,}
response = requests.get(url=url, headers=headers)

requests的其餘參數

除了url和之外還有不少參數,好比timeout、代理IP等等

requests請求的超時參數——timeout

配合異常捕獲,在指定時間返回響應

# 在三秒內必須返回響應,不然則會報錯
response = requests.get(url=url,headers=headers,timeout=3)

創建代理

  • 創建代理
proxies = [{"http":"113.122.8.45:53128"},{"http":"114.122.8.45:53128"},{"http":"115.122.8.45:53128"}]
  • 導入隨機數模塊
proxy = random.choice(proxies)

response的方法:

經過response獲取頁面的響應內容,包括響應頭、響應體。

這是咱們所使用的公共代碼:

import requests
url = 'https://www.cnblogs.com/Asterism-2012/'
response = requests.get(url=url)

獲取源代碼

  • response.content
    第一種狀況,使用content方法獲取源代碼,可是這種方式是以byte的方式獲取源代碼,先看一下它是什麼,看完這個咱們稍後對它解碼
print(response.content)

Terminal:

b'\r\n<!DOCTYPE html>\r\n<html lang="zh-cn">\r\n<head>\r\n<meta ......略
  • response.content.code()

咱們發現剛纔打印的content內容是byte,爲了便於觀看,進行解碼:
它會將content的內容解碼爲str類型,也能夠自行指定解碼類型。

x = response.content.decode()
print(type(x))
print(x)

Terminal:

<class 'str'>
略......<p>by: 魏泯</p><!--PageEndHtml Block End--></body></html>

decode()自行指定content解碼類型:

x= response.content.decode('utf-8')
print(type(x))

Terminal:

<class 'str'>
  • response.text

使用text方法獲取到的源代碼,是根據HTTP 頭部對響應的編碼做出有根據的推測,推測的文本編碼。這種方法簡單經常使用,適用於大部分的網站。固然既然是推測的代碼,就也有出現錯誤的時候,這也不要緊,到時候咱們能夠經過指定編碼來解決這個問題。

print(response.text)

Terminal:

略......<p>by: 魏泯</p><!--PageEndHtml Block End--></body></html>

設置服務器的編碼爲本地的編碼

可是有的時候即使進行了解碼,也沒法正常看到頁面源碼。形成這樣的緣由是本地編碼與服務器編碼不統一,因此咱們要對響應回來的內容制定編碼。

  • 第一種方式,自動獲取:
response.encoding = response.apparent_encoding
  • 第二種方式,手動抓包設置,假設以抓到的是gbk爲例:
response.encoding=」gbk」

請求與響應的目標url地址

  • 請求目標站點的Url:

有時候咱們須要獲取到目標站點的url,用於拼接新的url或者作保存、跳轉等工做,因此就用到了response.request.url
這個方法

x = response.request.url

Terminal:

https://www.cnblogs.com/Asterism-2012/
  • 實際發生響應的Url地址:

響應的url地址,有時候會由於跳轉而和請求目標地址不一致,使用response.url方法來獲取它:

x = response.url
print(x)

Terminal:

https://www.cnblogs.com/Asterism-2012/

請求與響應的頭部信息

  • 查看請求頭部信息:

有時候咱們須要測試本身的代理IP池、Header池信息,就能夠經過這個方法來動態獲取頭部信息進行查看

x = response.request.headers
print(x)

Terminal:

{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
  • 查看響應頭部信息:
x = response.headers
print(x)

Terminal:

{'Date': 'Fri, 04 Jan 2019 03:53:18 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'Cache-Control': 'private, max-age=10', 'Expires': 'Fri, 04 Jan 2019 03:53:28 GMT', 'Last-Modified': 'Fri, 04 Jan 2019 03:53:18 GMT', 'X-UA-Compatible': 'IE=10', 'X-Frame-Options': 'SAMEORIGIN', 'Content-Encoding': 'gzip'}

處理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:(這應是最經常使用的方法)
    1. session = requests.session() 會話保持,實例session
    2. session.post(post_url,data,headers) 不少網頁的接口能夠在表單的action提交地址中看到,但有一些須要抓包才能看到
    3. response = session.get(url,headers)
    • 使用session不只能夠處理相關登錄,並且能夠應對相關反爬措施。
  • 處理登錄相關的驗證碼能夠找:打碼兔

*返回目錄再看看*


數據提取方法

JSON

  • 數據交換格式,在Python的識別中實際上是一個字符串
  • 學習處理和操縱json數據,很是重要
  • 導入標準庫模塊jsonimport 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溯源僞造
    有些網址的反爬策略是:某些網址的特定網頁會識別客戶端的refer信息,這些信息包含了客戶端的請求記錄。它的具體意思是,你必須經由訪問了個人主頁,跳轉到個人子頁面,而不是從URL直接過來。你先開我家門,才能到個人臥室,而不是從窗戶進來。不然就認爲你是不合法的。
headers = {
'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()

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

Retrying 模塊

retrying是一個第三方模塊,用於重試出現異常的函數。
首先進行安裝:

pip install retrying (安裝)

代碼示例(「出事了算個人,你儘管去作,作錯了也不怕,但最多三次」):

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.")

開發一個微型ORM(對象關係映射)腳本【源代碼】

#coding=utf-8
'''微型ORM v1.1
@help:
首先要保證你的items中的鍵值與數據庫中的字段吻合,其次要本身創建庫和數據表,
傳入你的item,而且傳入表的名稱
@Form: 魏泯
'''

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語句

*返回目錄再看看*

相關文章
相關標籤/搜索