「Python爬蟲系列講解」3.正則爬蟲之牛刀小試

做者 : 榮仔!最靚的仔!
專欄地址 :
http://suo.im/5Rh1z1html

本文目錄

1 re模塊

正則表達式(Regular Expression, Regex 或 RE)又稱正規表示法或常規表示法,經常使用來檢索、替換那些符合某個模式的文本。python

它首先設定好一些特殊的字符及字符組合,而後經過組合的「規則字符串」來對錶達式進行過濾,從而獲取或匹配用戶想要的特定內容。git

1.1 re模塊

Python 經過 re 模塊提供對正則表達式的支持,但在使用正則表達式以前須要導入 re 模塊才能調用該模塊的功能函數。github

import re

其基本步驟是:web

  • 將正則表達式的字符串形式編譯爲 pattern 實例;
  • 使用 pattern 實例處理文本並得到一個匹配實例;
  • 使用 match 實例得到所需信息;

經常使用函數是 findall,原型以下:正則表達式

findall(String[, pos[, endpos]])|re.findall(pattern, string[, flags])

該函數表示搜索字符串 string,而後以列表形式返回所有匹配字符串。編程

其中,參數 re 包括3個常見值。(括號內是完整寫法)json

re.I(re.IGNORECASE)  # 使匹配忽略大小寫
re.M(re.MULTILINE)   # 容許多行匹配
re.S(re.DOTALL)      # 匹配包括換行在內的全部字符

另外,pattern 對象是一個編譯好的正則表達式,經過 pattern 提供的一系列方法能夠對文本進行匹配查找;pattern 對象不能直接實例化,必須使用 re.compile() 進行構造。瀏覽器

1.2 complie方法

re 模塊包括一些經常使用的操做函數,好比 complie() 函數,其原型以下:安全

re.compile(pattern[, flags])

該函數根據包含正則表達式的字符串建立模式對象,返回一個 pattern 對象。其中,參數 flags 是匹配模式,可使用按位或「|」表示同時生效,也能夠在正則表達式字符串中指定。

# 舉例說明如何使用正則表達式來獲取字符串中的數字內容
import re
string = 'A1.45, b5, 6.45, 8.82'
regex = re.compile(r"\d+\.?\d*")
print(regex.findall(string))

結果以下:

1.3 match方法

match 方法是從字符串的 pos 下標處開始匹配 pattern,若是 pattern 結束時已經匹配,則返回一個 match 對象;若是匹配過程當中 pattern 沒法匹配,或者匹配未結束就已達到 endpos,則返回 None。

match 方法原型以下:

match(string[, pos[, endpos]]) | re.match(patter, string[, flags])

其中,參數 string 表示字符串;pos 表示下標,pos 和 endpos 的默認值分別爲 0 和 len(string);參數 flags 用於編譯 pattern 時指定匹配模式。

1.4 search方法

search 方法用於查找字符串中能夠匹配成功的子字符串。從字符串的 pos 下標處嘗試匹配 pattern,若是 pattern 結束時仍可匹配,則返回一個 match 對象,若是 pattern 結束時仍沒法匹配,則將 pos 加 1 後從新嘗試匹配,若知道 pos = endpos 時仍沒法匹配,則返回 None。

search 方法函數原型以下:

search(string[, pos[, endpos]]) | re.search(pattern, string[, flags])

其中,參數 string 表示字符串;pos 表示下標,pos 和 endpos 的默認值分別爲 0 和 len(string);參數 flags 用於編譯 pattern 時指定匹配模式。

1.5 group和groups方法

group([group1, …]) 方法用於得到一個或多個分組截獲的字符串,當它指定多個參數時將以元組形式返回 None,截獲屢次的組返回最後一次截獲的字符串。

groups([default]) 方法以元組形式返回所有分組截獲的字符串,至關於屢次調用 group,其中參數 default 表示沒有截獲字符串的組以該值代替,默認爲 None。

2 Python網絡數據爬取的經常使用模塊

2.1 urllib模塊

urllib 是 Python 用於獲取 URL(Uniform Resource Locators,贊成資源定位器)的庫函數,能夠用於爬取遠程的數據並保存,甚至能夠設置消息頭(header)、代理、超時認證等。

urllib 模塊提供的上策接口使用戶可以像讀取本地文件同樣讀取 WWW 或 FTP 上的數據,使用起來比C++、C#等編程語言更加方便。

2.1.1 urlopen

函數原型以下:

urlopen(url, data = None, proxies = None)

該方法用於建立一個遠程 URL 的類文件對象,而後像本地文件同樣操做這個類文件對象來獲取遠程數據。其中參數 url 表示遠程數據的路徑,通常是網址;參數 data 表示以 post 方式提交到 url 的數據;參數 proxies 用於設置代理;返回值是一個類文件對象。

本實例用來介紹 urllib 庫函數爬取百度官網的實例


import urllib.request
import webbrowser as web
 
url = 'http://www.baidu.com'
content = urllib.request.urlopen(url)  # 打開連接
 
print(content.info)     # 頭信息
print(content.geturl)   # 請求url
print(content.getcode)  # HTTP狀態碼
 
# 保存至本地並經過瀏覽器打開
response = urllib.request.urlopen(url).read()
open('baidu.html''w').write(response.decode('UTF-8'))

結果以下:

2.1.2 urlretrieve

urlretrieve 方法是將遠程數據下載到本地,函數原型以下:

urlretrieve(url, filename = None, reporthook = None, data = None)

其中,參數 filename 指定了保存到本地的路徑,若是省略該函數,則 urllib 會自動生成一個臨時文件來保存數據;

參數 reporthook 是一個回調參數,當鏈接上服務器,響應的數據塊傳輸完畢時,會觸發該調回函數,一般使用該回調函數來顯示當前的下載進度;

參數 data 是指傳遞到服務器的數據。

本實例用來演示如何將新浪首頁爬取到本地,並保存在「F:/sina.html」文件中,同時顯示下載進度。

from urllib.request import urlretrieve
 
# 設置函數來表示下載文件至本地,並顯示下載進度
def Download(a, b, c):
    # a--已經下載的數據塊
    # b--數據塊的大小
    # c--遠程文件的大小
    per = 100.0 * a * b / c
    if per >100:
        per = 100
    print('%.2f%%' % per)
 
url = 'http://www.sina.com.cn'
local = 'F:/sina.html'
urlretrieve(url, local, Download)

結果以下:

2.2 urlparse模塊

urlparse 模塊主要是對 url 進行分析,其主要的操做時拆分和合並 url 各個部件。它能夠將 url 拆分紅 6 個部分,並返回元組,也能夠把拆分後的部分再組成一個 url。

urlparse 模塊包括的函數主要有 urlparse、urlunparse 等。

# python3版本中已經將urllib二、urlparse、和robotparser併入了urllib模塊中,而且修改urllib模塊
from urllib.parse import urlunparse
from urllib.parse import urlparse
2.2.1 urlparse函數

函數原型以下:

urlparse(urlstring[, scheme[, allow_fragments]])

該函數將 urlstring 值解析成 6 各部分,從 urlstring 中獲取 URL,並返回元組(scheme,netloc,path、params、query、fragment)。該函數可用於肯定網絡協議(HTTP、FTP等)、服務器地址、文件路徑等。

from urllib.parse import urlparse
 
url = urlparse('https://blog.csdn.net/IT_charge/article/details/105714745')
 
# 輸出內容包括如下六個部分scheme, netloc, path, params, query, fragment
print(url)
print(url.netloc)

結果以下:

2.2.2 urlunparse函數

一樣能夠調用 urlunparse() 函數將一個元祖內容構建成一條 url,函數原型以下:

urlunparse(parts)

該元組相似 urlparse 函數,它接收元組(scheme, netloc, path, params, query, fragment)後,會從新組成一個具備正確格式的URL,以便共 Python 的其餘 HTML 解析模塊使用。

from urllib.parse import urlunparse
from urllib.parse import urlparse
 
url = urlparse('https://blog.csdn.net/IT_charge/article/details/105714745')
 
# 輸出內容包括如下六個部分scheme, netloc, path, params, query, fragment
print(url)
print(url.netloc)
 
# 重組url
u = urlunparse(url)
print(u)

結果以下:

2.3 requests模塊

requests 模塊是用 Python 語言編寫的、基於 urllib 的第三方庫,其採用 Apache2 Licensed 開源協議的 HTTP 庫。它比 urllib 更加方便,既能夠節約大量的工做,又徹底知足 HTTP 的測試需求。

安裝 requests 模塊方法

pip install requests
2.3.1 導入requests模塊

使用語句以下:

import requests
2.3.2 發送GET/POST請求

requests 模塊能夠發送 HTTP 的兩種請求,GET 請求和 POST 請求。其中 GET 請求能夠採用 url 參數傳遞數據,它從服務器上獲取數據,而 POST 請求是向服務器傳遞數據,該方法更爲安全。

# 這裏給出 get 和 post 請求獲取某個網站網頁的方法,獲得一個命名爲 response 的響應對象,經過這個對象獲取咱們所須要的信息
r = requests.get('https://github.com/timeline.json)
r = requests.post('
https://httpbin.org/post)
2.3.3 傳遞參數

url 一般會傳遞某種數據,這種數據採用鍵值對的參數形式置於 URL 中。

requests經過 params 關鍵字設置 URL 的參數,以一個字符串字典來提供這些參數。

# 傳遞 key1=value1 和 key2=value2 到 httpbin.org/get 後
import requests
 
payload = {'key1''value1''key2''value2'}
r = requests.get('http://httpbin.org/get', params = payload)
print(r.url)

結果以下:

2.3.4 相應內容

requests 會自動解碼來自服務器的內容,而且大多數 Unicode 字符集都能被無縫解碼。當請求發出後,requests 會基於 HTTP 頭部對響應的編碼作出有根據的推測。

import requests
r = requests.get('https://github.com/timeline.json')
print(r.text)

結果以下:

2.3.5 定製請求頭

只須要簡單地傳遞一個字典(dict)給消息頭 headers 參數便可。以網站「堆糖」爲例,其 headers 參數在 User-Agent 裏找。

定製請求頭是爲了假裝爬蟲程序,不會被網站輕易檢測出來,亦即不會返回 403 錯誤。

演示以下:

# 這裏假設給 堆糖 網站指定一個消息頭
import requests
 
base_url = 'https://www.duitang.com/'
headers = {
    'User-Agent''Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
}
response = requests.get(url=base_url, headers=headers)
print(response)

結果以下:

3 正則表達式爬取網絡數據的常見方法

3.1 爬取標籤間的內容

HTML語言是採用標籤對的形式來編寫網站的,包括起始標籤和結束標籤,好比、、等。

3.1.1 爬取title標籤間的內容

首先能夠採用正則表達式「‘’」來爬取起始標籤之間的內容。

# 本實例用來爬取百度官網標題——「百度一下,你就知道」
import re
import requests
url = 'https://www.baidu.com/?tn=78040160_5_pg&ch=8'
response = requests.get(url).content.decode('utf-8')
title = re.findall(r'<title>(.*?)</title>', response)
print(title[0])

結果以下:

3.1.2 爬取超連接標籤間的內容

在 HTML 中, 超連接標題 用於表示超連接。

import re
import requests
 
url = "http://www.baidu.com"
content = requests.get(url).content.decode('utf-8')
 
# 獲取完整的超連接
res1 = re.compile('<a(.*?)</a>')
urls1 = re.findall(res1, content)
for u1 in urls1:
    print(u1)
 
# 獲取超連接<a>和</a>之間的內容
res2 = re.compile('<a.*?>(.*?)</a>')
urls2 = re.findall(res2, content)
for u2 in urls2:
    print(u2)

結果以下:

3.1.3 爬取re標籤和td標籤間的內容

網頁經常使用的佈局包括 table 佈局和 div 佈局,其中,table 佈局中常見的標籤包括tr,th和td,tr(table row)表示表格行爲,td(table data)表示表格數據,th(table heading)表示表格表頭。

首先假設存在下面這樣一個HTML代碼。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>表格</title>
</head>
<body>
<table border="1">
    <tr><th>編號</th><th>課程名</th></tr>
    <tr><td>001</td><td>Python程序設計語言</td></tr>
    <tr><td>002</td><td>JavaScript</td></tr>
    <tr><td>003</td><td>網絡數據爬取及分析</td></tr>
</table>
</body>
</html>

結果以下:

此時,看看怎麼使用Python代碼獲取上述信息呢?

import re
 
# 獲取<tr> </tr>之間的內容
f = open("t.html","r",encoding="utf-8"# 讀取文件
f = f.read()         # 把文件內容轉化爲字符串
trs = re.findall(r'<tr>(.*?)</tr>', f, re.S|re.M)
for tr in trs:
    print(tr)
 
# 獲取<th> </th>之間的內容
print('\n')
for m in trs:
    ths = re.findall(r'<th>(.*?)</th>', m, re.S|re.M)
    for th in ths:
        print(th)
 
# 獲取<td> </td>之間的內容
print('\n')
tds = re.findall(r'<td>(.*?)</td><td>(.*?)</td>', f, re.S|re.M)
for td in tds:
    print(td[0], td[1])

結果以下:

3.2 爬取標籤中的參數

3.2.1 爬取超連接標籤的URL

HTML超連接的基本格式爲 「 連接內容 」。

import re
 
content = '''
<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新聞</a>
<a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a>
<a href="http://map.baidu.com" name="tj_trmap" class="mnav">地圖</a>
'''

 
res = r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')"
urls = re.findall(res, content, re.I|re.S|re.M) 
for url in urls:
    print(url)

結果以下:

3.2.2 爬取圖片超連接標籤的URL

在HTML中,咱們能夠看到各式各樣的圖片,其中圖片標籤的基本格式爲「 <img src = 圖片地址/> 」 ,只有經過爬取這些圖片原地址,才能下載對應的圖片至本地。

import re
 
content = '''
<img alt = "meizi" src = "http://img.ivsky.com/img/tupian/pre/202001/15/gancaoduo-002.jpg"/>
'''

 
res = '<img .*? src = "(.*?)"/>'
urls = re.findall(res, content, re.I|re.S|re.M)
print(urls)

結果以下:

3.2.3 獲取URL中的最後一個參數

在使用 Python 爬取圖片的過程當中,一般會遇到圖片對應的 URL 最後一個字段用來對圖片命名的狀況,如前面的「gancaoduo-002.jpg」,所以就須要經過解析 URL 「/」 後面的參數來獲取圖片名字。

import re
 
content = '''
<img alt = "meizi" src = "http://img.ivsky.com/img/tupian/pre/202001/15/gancaoduo-002.jpg"/>
'''

 
# res = '<img .*? src = "(.*?)"/>'
# urls = re.findall(res, content, re.I|re.S|re.M)
# print(urls)
 
urls = 'http://img.ivsky.com/img/tupian/pre/202001/15/gancaoduo-002.jpg'
# 採用「/」分隔字符串,進而獲取最後一個值
picture_name = urls.split('/')[-1]
print(picture_name)

結果以下:

3.3 字符串處理及替換

當使用正則表達式爬取網頁文本時,首先須要調用 find() 函數來找到指定的位置,而後在進行進一步爬取。

# 好比先獲取class屬性爲「infobox」的表格table,而後再進行定位爬取
start = content.find(r'<table class="infobox>')   # 起點位置
end = content.find(r'</table>')                   # 終點位置
infobox = text[start:end]
print(infobox)

在爬取過程當中可能會爬取無關變量,此時須要對無關內容進行過濾,這裏推薦使用replace()函數和正則表達式進行處理。

import re
 
content = '''
    <tr><td>000</td><td>軟件工程</td></tr>
    <tr><td>001</td><td>Python程序設計語言<br/></td></tr>
    <tr><td>002</td><td><B>JavaScript</B></td></tr>
    <tr><td>003</td><td>網絡數據 &nbsp; 爬取及分析</td></tr>
'''

 
res = r'<td>(.*?)</td><td>(.*?)</td>'
texts = re.findall(res, content, re.S|re.M)
for text in texts:
    print(text[0], text[1])

結果以下:

此時須要過濾掉多餘的字符串,如換行()、空格( )、加粗(),過濾代碼以下。

import re
 
content = '''
    <tr><td>000</td><td>軟件工程</td></tr>
    <tr><td>001</td><td>Python程序設計語言<br/></td></tr>
    <tr><td>002</td><td><B>JavaScript</B></td></tr>
    <tr><td>003</td><td>網絡數據 &nbsp; 爬取及分析</td></tr>
'''

 
res = r'<td>(.*?)</td><td>(.*?)</td>'
texts = re.findall(res, content, re.S|re.M)
for text in texts:
    value0 = text[0].replace('<br/>'"").replace('&nbsp;'"")
    value1 = text[1].replace('<br/>'"").replace('&nbsp;'"")
    if '<B>' in value1:
        text_value = re.findall(r'<B>(.*?)</B>', value1, re.S|re.M)
        print(value0, text_value[0])
    else:
        print(value0, value1)

結果以下:

採用 replace() 函數將字符串 「」 和 「< >」 轉換成空白實現過濾,而加粗()則須要使用正則表達式進行過濾 。

4 本文總結

正則表達式經過組合的「規則字符串」對錶達式進行過濾,從複雜內容中匹配想要的信息。它的主要對象是文本,適合文本字符串等內容,好比匹配URL、E-mail這種純文本的字符,但不是和匹配文本意義。各類編程語言都能使用正則表達式,好比C#、Java、Python等。

正則表達式爬蟲經常使用於獲取字符串中的某些內容,好比提取博客閱讀量和評論數等數字,截取URL中的某個參數,過濾掉特定的字符或檢查所獲取的數據是否符合某個邏輯,驗證URL或日期類型等。因爲其具備靈活性、邏輯性和功能性較強的特色,從而可以迅速地以極簡單地方式從複雜字符串中匹配到想要的信息。

最後再補充一點,在Python網絡數據爬取中,與 re 模塊(正則表達式)有一樣功能的還有 xpath、BeautifulSoup等。

未完,待續......

若是你以爲本文寫得好,能夠掃描下方二維碼,關注做者的CSDN博客,更多精彩文章搶先看。

     

關注微信公衆號『數據分析與統計學之美』,添加做者微信號,拉你入羣哦,氣氛槓槓的!看到這裏,麻煩您點個再看,讓更多朋友看到哦!

喜歡本文點個在看

本文分享自微信公衆號 - 數據分析與統計學之美(gh_21c25c7e71d0)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索