1. 程式人生 > >【網路爬蟲的三種解析方式】

【網路爬蟲的三種解析方式】

三種解析方式

  1. 正則解析
  2. Xpath解析
  3. BeautifulSoup解析

本文將詳細為大家講解三種聚焦爬蟲中的資料解析方式。

requests模組可實現資料爬取的流程


  1. 指定url
  2. 基於requests模組發起請求
  3. 獲取響應物件中的資料
  4. 進行持久化儲存


       其實,在上述流程中還需要較為重要的一步,就是在持久化儲存之前需要進行指定資料解析。因為,在大多數情況下,我們都是指定去使用聚焦爬蟲,也就是爬取頁面中指定部分的資料值,而不是整個頁面的資料。因此,本文將詳細為大家講解三種聚焦爬蟲中的資料解析方式。至此,我們的資料爬取流程可以修改為:

  1. 指定url
  2. 基於requests模組發起請求
  3. 獲取響應中的資料
  4. 資料解析
  5. 進行持久化儲存

正則解析

注:這裡將從Python語言的視角講解


re.I 忽略大小寫
re.M 多行匹配
re.S 單行匹配

.* 貪婪模式
.*? 非貪婪(惰性)模式

? 0次或1次
+ 1次或多次
* 0次或1次或多次

{m} 固定m次
{m, } 至少m次
{m, n} m-n次

(\d?) 分組
(?P<name>\d?) 分組命名
(?P=name) 引用前面定義的命名分組
(?:\d?)

取消分組優先
(\d?)\1\1 通過預設分組編號向後引用(這裡將匹配3個相同的數字)
(?<=pattern) 向後肯定斷言的語法


關於正則的更多介紹,可見此文獻:【正則表示式介紹篇】

Xpath解析

pip install lxml


示例

我們先準備好用於測試的HTML頁面:

<html lang="en">
<head>
	<meta charset="UTF-8" />
	<title>Xpath解析測試</title>
</head>
<body
>
<div> <p>百里守約</p> </div> <div class="song"> <p>李清照</p> <p>王安石</p> <p>蘇軾</p> <p>柳宗元</p> <a href="http://www.song.com/" title="趙匡胤" target="_self"> <span>this is span</span> 宋朝是最強大的王朝,不是軍隊的強大,而是經濟很強大,國民都很有錢</a> <a href="" class="du">總為浮雲能蔽日,長安不見使人愁</a> <img src="http://www.baidu.com/meinv.jpg" alt="" /> </div> <div class="tang"> <ul> <li><a href="http://www.baidu.com" title="qing">清明時節雨紛紛,路上行人慾斷魂,借問酒家何處有,牧童遙指杏花村</a></li> <li><a href="http://www.163.com" title="qin">秦時明月漢時關,萬里長征人未還,但使龍城飛將在,不教胡馬度陰山</a></li> <li><a href="http://www.126.com" alt="qi">岐王宅裡尋常見,崔九堂前幾度聞,正是江南好風景,落花時節又逢君</a></li> <li><a href="http://www.sina.com" class="du">杜甫</a></li> <li><a href="http://www.dudu.com" class="du">杜牧</a></li> <li><b>杜小月</b></li> <li><i>度蜜月</i></li> <li><a href="http://www.haha.com" id="feng">鳳凰臺上鳳凰遊,鳳去臺空江自流,吳宮花草埋幽徑,晉代衣冠成古丘</a></li> </ul> </div> </body> </html>

開始測試:

from lxml import etree  # pip install lxml

# 本地檔案
tree = etree.parse('test01.html')
# 如果是網路檔案,應使用etree.HTML()


# 1.取出class為song的div標籤下的所有文字內容
ret01 = tree.xpath('//div[@class="song"]//text()')
# //text() 表示取出某個標籤下文字內容和所有子標籤下的文字內容,如果存在文字,則返回的是單個元素的列表


# 2.取出class為tang的div下的直系子標籤ul下的直系子標籤第二個li下的直系子標籤a標籤下的內容
ret02 = tree.xpath('//div[@class="tang"]/ul/li[2]/a/text()')
# /text() 表示取出某個標籤下的文字內容,如果存在文字,則返回的是單個或多個元素的文字
# li[2] 表示取第2個li標籤

# 3.取出href屬性值為空 且 class屬性值為du的a標籤內的文字內容
ret03 = tree.xpath('//a[@href="" and @class="du"]/text()')
# 邏輯運算:and

# 4.取出class包含 ta 的div標籤下的所有文字內容(包括子孫標籤)
ret04 = tree.xpath('//div[contains(@class, "ta")]//text()')
ret05 = tree.xpath('//div[starts-with(@class, "ta")]//text()')
# 模糊匹配:contains(@class, "ta") 或 starts-with(@class, "ta")

# 5.取出class為tang的div標籤下的任意標籤下li標籤(第2個)下的a標籤內href屬性的值
ret06 = tree.xpath('//div[@class="tang"]//li[2]/a/@href')

# 6. / 開頭的,表示最外層的標籤
ret07 = tree.xpath('/html/body/div[@class="tang"]//text()')

# 定位所有class為tang的div
tree.xpath('//div[@class="tang"]')  

# 7. .// 表示從當前標籤開始找
ret08 = tree.xpath('.//a/text()')

> # 8. | 表示或者
ret08 = tree.xpath('//div[@class="song"] | //div[@class="tang"]')

你還可以在瀏覽器中安裝xpaht外掛,以實現在瀏覽器中對xpath表示式進行驗證,以及通過html元素獲得xpath表示式。


例項:下載煎蛋網中的圖片

import os
import base64
import requests
from lxml import etree
import urllib.request  # 使用其來快速儲存內容
from fake_useragent import UserAgent  # 隨機UA


url = 'http://jandan.net/pic/page-%s#comments'  # 煎蛋網

headers = {
    'User-Agent': UserAgent(use_cache_server=False).random
}

page_text = requests.get(url=url % 1, headers=headers)  # 爬取第1頁的內容
page_text.encoding = 'utf-8'
content = page_text.text


# 檢視頁面原始碼:發現所有圖片的src值都是一樣的。
# 簡單觀察會發現每張圖片載入都是通過jandan_load_img(this)這個js函式實現的。
# 在該函式後面還有一個class值為img-hash的標籤,裡面儲存的是一組hash值,該值就是加密後的img地址
# 加密就是通過js函式實現的,所以分析js函式,獲知加密方式,然後進行解密。
# 通過抓包工具抓取起始url的資料包,在資料包中全域性搜尋js函式名(jandan_load_img),然後分析該函式實現加密的方式。
# 在該js函式中發現有一個方法呼叫,該方法就是加密方式,對該方法進行搜尋
# 搜尋到的方法中會發現base64和md5等字樣,md5是不可逆的所以優先考慮使用base64解密


tree = etree.HTML(content)

# 獲取所有加密的圖片地址
img_code_list = tree.xpath('//span[@class="img-hash"]/text()')

# 開始解密
img_url_list = []
for code_url in img_code_list:
    img_url = 'http:' + base64.b64decode(code_url).decode()
    img_url_list.append(img_url)

# 儲存圖片
dirname = '煎蛋圖'
os.mkdir(dirname)
for url in img_url_list:
    file_name = url.split('/')[-1]
    file_path = os.path.join(dirname, file_name)
    urllib.request.urlretrieve(url=url, filename=file_path)
    print(f'{file_path}已儲存')

BeautifulSoup解析