《毫無障礙學Python》鄧文淵著 學習筆記
web數據抓取與分析
1.網址解析
.
通過Python的 urlparse組件中的 urlparse函數,可對網址進行解析,其返回值爲元組類型的ResultParse對象,通過其對象的屬性可得到網地址中的個項數據
ResultParse函數屬性:
索引值 | 返回值 | 不存在的返回值 | |
---|---|---|---|
scheme | 0 | 返回scheme通訊協議 | 空字符串 |
netloc | 1 | 返回網站名稱 | 空字符串 |
path | 2 | 返回path路徑 | 空字符串 |
params | 3 | 返回url查詢參數((params)字符串 | 空字符串 |
query | 4 | 返回query字符串,即GET參數; | 空字符串 |
fragment | 5 | 返回框架名稱 | 空字符串 |
port | 6 | 返回通信端口 | None |
解析中國天氣網南昌天氣的網址:http://www.weather.com.cn/weather1d/101240101.shtml#input
from urllib.parse import urlparse
url = 'http://www.weather.com.cn/weather1d/101240101.shtml#input'
o = urlparse(url)
print(o)
print("scheme={}".format(o.scheme)) # http
print("netloc={}".format(o.netloc)) # www.weather.com.cn
print("port={}".format(o.port)) # None
print("path={}".format(o.path)) # /weather1d/101240101.shtml
print("query={}".format(o.query)) # 空
運行結果:
2.網頁數據抓取
.
requests用於抓取網頁源代碼,由於他比內置urllib模塊好用,因此逐漸取代了urllib,抓取源碼後可用in或正則表達式搜索獲取所需數據
導入requests,可用requests.get()函數模擬HTTP GET方法發出一個請求(Request)到遠程服務器(Server),當服務器接收請求後會響應(Response)並返回網頁內容(源代碼),設置正確的編碼格式,既可通過text屬性取得網址中源代碼。
(1) 獲取網頁源碼
import requests
url = 'http://music.taihe.com/' #以千千音樂網站爲例
html = requests.get(url) #print(type(html))爲<class 'requests.models.Response'>
#html.encoding='utf-8' #以utf-8編碼抓取
print(html.text) # html.text獲取網頁源碼
#取得網頁源碼後,即可對源碼加以處理,例:把每一行分割成列表並移除換行符
htmllist = html.text.splitlines() #每一行分割成列表並移除換行符
for row in htmllist:
print(row)
print(len(htmllist))
(2)搜索指定字符串
用text屬性取得的源碼爲一大串字符串 若想搜索其中指定 字符或字符串 可用in來完成
import requests
url = 'http://www.9ku.com/qingyinyue/' #以九酷音樂網爲例
html = requests.get(url)
html.encoding = 'utf-8'
if "流水" in html.text:
print("找到!")
##也可一行行搜索 ,並統計該字符串出現的次數
htmllist = html.text.splitlines()
n = 0
for row in htmllist:
if "流水" in row:n+=1
print('找到{}次'.format(n))
運行結果:
用正則表達式(regular expression簡稱regex)(對字符串操作的一種邏輯公式)抓取網站內容:複雜內容:超鏈接、電話號碼…
常見正則表達式 | |
---|---|
. | 表示一個除換行符(\n)外的所有字符 |
^ | 表示輸入行的開始 |
$ | 表示輸入行的結束 |
* | 表示前一個項目可以出現0次或無數次 |
+ | 表示前一個項目可以出現1次或無數次 |
? | 表示前一個項目可以出現0次或1次 |
[abc] | 表示一個符號a或b或c的任何字符 |
[a-z] | 表示一個符號a~z的任何字符 |
\ | 表示後面的字符以常規字符處理 |
{m} | 表示前面的項目必須正好出現m次 |
{m,} | 表示前面的項目至少出現m次,最多可出現無數次 |
{m,n} | 表示前面的項目至少出現m次,最多可出現n次 |
\d | 表示一個數字,相當於[0123456789]或[0-9] |
^ | 求反運算,例[^a-d]表示除a,b,c,d外的所有字符 |
\D | 一個非數字字符,即[^0-9] |
\n | 換行字 |
\r | 換行符 |
\t | tab製表符 |
\s | 空格符,即[\r\t\n\f] |
\S | 非空格符,即[^\r\t\n\f] |
\w | 一個數字、字母或下劃線字符,相當於[0-9a-zA-Z_] |
\W | 一個非數字、字母或下劃線字符,即[\w]即[0-9a-zA-Z] |
常見的正則表達式實例
正則表達式 | 實例 | |
---|---|---|
整數 | [0-9]+ | 12356 |
帶小數點的實數 | [0-9]+.[0-9]+ | 45.26 |
英文字符串 | [A-Za-z]+ | Python |
變量名稱 | [A-Za-z_][A-Za-z0-9_] | _point |
Emial | [a-zA-Z0-9]+@[a-zA-Z0-9._]+ | [email protected] |
URL | http://[a-zA-Z0-9./_]+ | http://e-happy.com.tw/ |
.
創建正則表達式對象:要使用正則表達式首先需導入re包,再用re包提供的compile方法創建一個正則表達式對象
語法:import re
pat = re.compile(’[a-z]+’)
正則表達式對象包含的方法:
match(string) 在string中查找符合正則表達式的規則的字符串,遇到第一個不符合的字符時結束,結果會存入match對象(object)中;若未找到符合的字符,返回None
match對象包含的方法:
- group() 返回符合正則表達式的字符串,遇到第一個不符合的字符時結束,結果存入match對象(object)中;未找到符合字符返回None
- end() 返回match的結束爲置
- span() 返回(開始位置,結束位置)的元組對象
import re
pat = re.compile('[a-z]+')
m = pat.match('tem12po') #簡單起見,將match對象的值賦值給m
print(m)
print(m.group())
print(m.start())
print(m.end())
print(m.span())
## re.match()方法:(可省略re.match()方法創建正則表達式的步驟)
import re
m = re.match(r'[a-z]+','tem12po') #兩個參數,第一個習慣在參數前加‘r'告訴編譯器這個是正則表達式,第二個參數傳遞待搜索的字符串
print(m)
search(string) 在string中查找第一組符合正則表達式的字符串,找到後結束,結果存入match對象(object)中;若未找到符合的字符,返回None
## search(string) 在string中查找第一組符合正則表達式的字符串,找到後結束,結果存入match對象
# (object)中;若未找到符合的字符,返回None
import re
pat = re.compile('[a-z]+')
m = pat.search('3tem12po')
print(m) #<_ser.SER_Match object;span=9(1,4),match='tem'>
if not m==None:
print(m.group()) # tem
print(m.start()) # 1
print(m.end()) # 4
print(m.span()) # (1,4)
## findall() 返回指定字符串中所有符合正則表達式的字串,並返回一個列表
import re
pat = re.compile('[a-z]+')
m = pat.findall('tem12po')
print(m) # ['tem','po']
案例:抓取萬水書苑網站中所有E-mail賬號
import requests,re
regex = re.compile(r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+') #建立正則表達式對象
url = 'http://www.wsbookshow.com/'
html = requests.get(url) #抓取http://wsbookshow.com/網站的源代碼
emails = regex.findall(html.text) #在html.text中查詢所有Email賬號
for email in emails:
print(email)
(3)網頁分析
網頁分析:HTML網頁結構:許多標籤組成<>
使用BeautifulSoup進行網頁抓取與解析
導入BeautifulSoup後,先用requests包中的get方法取得網頁源碼,然後可用Python內建的html.parser解析器對源代碼進行解析,解析結果返回到BeautifulSoup對象sp中,語法:sp = BeautifulSoup(源代碼,‘html.parser’)
import requests,urllib3
from bs4 import BeautifulSoup
url = 'http://www.baidu.com'
html = requests.get(url)
html.encoding='utf-8'
sp = BeautifulSoup(html.text,'html.parser')
BeautifulSoup常用屬性和方法:(假設已創建BeautifulSoup類的對象sp)
屬性和方法 | |
---|---|
title | 返回網頁標題 |
text | 返回除去所有HTML標籤後的網頁內容 |
find | 返回第一個符合條件的標籤,例:sp.find(“a”) |
find_all() | 返回所有符合條件的標籤,例:sp.find_all(“a”) |
select() | 返回指定CSS樣式(如id或class)的內容,返回值爲列表!,例:sp.select("#id")通過id抓取 |
data1 = sp.select('title')
print(data1)
data2 = sp.select('#head')#抓取id="head"的網頁源代碼內容 id注意加“#”
#print(data2)
data3 = sp.select(".head_wrapper")#可通過css類的類名head_wrapper進行搜索 class注意加“.”
#print(data3)
data4 = sp.find('a')#取得第一個標籤爲a的內容
#print(data4)
data5 = sp.find_all('a')#取得所有標籤爲a的內容
#print(data5)
# find_all(屬性名稱:屬性內容)可抓取所有符合規定的tag(標籤)內容,第二個參數是字典數據類型,
data5 = sp.find_all("a",{"class":"mnav"})
#print(data5[0])
#通過一個列表參數可以一次搜索多個標籤
data6 = sp.find_all(['a','title'])#用[]括起標籤名!
#print(data6)
抓取屬性內容:要抓取屬性內容必須使用get()方法
語法:get(屬性名稱)
import requests
from bs4 import BeautifulSoup
url = 'http://www.baidu.com/'
html = requests.get(url)
html.encoding = 'gbk'
sp = BeautifulSoup(html.text,'html.parser')
links = sp.find_all(['a','img']) #同時抓取<a>和<img>
for link in links:
href = link.get("href")#讀取href屬性值
# 判斷是否爲非None,及是否以http://開頭
if href != None and href.startswith("http://"):
print(href)
運行結果: