python爬取身份證資訊、爬取ip代理池
匹配的分類
按照匹配內容進行匹配
我們在匹配的過程當中,按照要匹配的內容的型別和數量進行匹配
比如:
匹配手機號:匹配以1開頭的11位數字
Re
按照匹配結構進行匹配
我們我們在匹配的過程當中,按照要匹配的內容在整個資料當中的結構進行匹配
比如:
匹配手機號:匹配phone:之後的值
Xpath
Beautifulsoup 是一個匹配的結合體,我們使用beautifulsoup可以完成內容和結構任意匹配。
內容匹配,匹配繁瑣,匹配精度高
機構匹配,匹配精度不高,匹配效率高,一定是成結構的字元
re正則
正則是通過對字串內容描述進行資料篩選的高階字串處理方式
在學習Python爬蟲的時候,初學同學會認為非正則不可,其實一部分簡單的匹配結構用的最多的方法是字串的:split、replace方法
內容的型別
#每個型別預設匹配1次
\d 匹配數字
\D 匹配非數字
\s 匹配空格
\S 匹配非空格
\w 匹配字母、數字、下劃線
\W 匹配非字母、數字、下劃線
[] 匹配任意字元
| 匹配任意一端
[^] 匹配非
. 匹配任意非換行的字元
^ 匹配開頭
$ 匹配結尾
() 組匹配
內容的長度
長度描述居於內容描述之後
如果有多次,指儘量多的匹配
如果匹配0次,代表沒有匹配到
* 匹配0到多次
+ 匹配1到多次
? 匹配0到1次
{} 匹配指定值或者範圍次
貪婪匹配
匹配的方法
Findall
Search
Match
正則例子:
例1:
一個正常的正則匹配,匹配一個網頁上所有的身份證號,最簡單
匹配身份證號,一般是匹配數字,但是要小心最後有x
首先編寫如下程式碼:
import re
import requests
# 請求地址
url = "http://sfz.ckd.cc/"
# 請求頭
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36"
}
# 獲取響應
response = requests.get(url = url,headers = headers)
# 獲取內容,這裡返回的是位元組,所以需要decode進行解析
content = response.content.decode()
# print(content)
# 利用正則粗糙的匹配
res = re.findall(r'\d+',content)
for re in res:
# 列印內容
print(re)
效果如下:
效果差強人意,所以改進,我們認真研究發現,身份證有18,但是數字個數是17-18位,因為最後一位可能是大小寫的X
程式碼如下:
import re
import requests
# 請求地址
url = "http://sfz.ckd.cc/"
# 請求頭
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36"
}
# 獲取響應
response = requests.get(url = url,headers = headers)
# 獲取內容,這裡返回的是位元組,所以需要decode進行解析
content = response.content.decode()
# print(content)
# 利用正則粗糙的匹配
# res = re.findall(r'\d+',content)
res = re.findall(r"\d{17}x|\d{17}X|\d{18}",content)
for re in res:
# 列印內容
print(re)
效果如下:
其實上面的正則可以寫成這樣:
res = re.findall(r"\d{17}[xX]|\d{18}",content)
效果如下:
一個組匹配
需要獲取完整的身份證資訊
如下:
爬蟲的正則匹配和其他的正則匹配區別在於,我們可以藉助HTML結構進行匹配
res = re.findall(r"<td>(.*?)</td><td>(.*?)</td><td>(.*)",content,re.M)
效果如下:
Search與match
- 區別(是python 2015年度北京市爬蟲面試第一頻繁的面試題)
Search是從全文查詢符合匹配的,match是從開頭查詢符合的,二者如果查詢到都需要用group來解析內容,如果查詢不到,都返回None
2. Group和groups
res = re.search(r"<td>(.*?)</td><td>(.*?)</td><td>(.*)",content,re.M)
print(res.group())
print(res.groups())
效果如下:
Lxml匹配
Python的xpath是通過lxml模組進行定義的,不論用beautifulsoup還是scrapy都需要我們下載lxml包。
pip install lxml
通過lxml我們進行爬蟲匹配大概分為2步
- 構建HTML結構,將返回的字串從新轉換為HTML
- 進行匹配
匹配的常用語法
1.節點名稱匹配
直接描述HTML節點
P div
2. 子節點描述
/Html/body/div
這樣的表述必須是相鄰父子關係,禁止誇層
3. 節點描述
[]
可以通過索引或者屬性描述節點
Html/body/div[1] HTML下的body下的第一個div
4. 節點屬性描述
[@屬性=“值”]
Html/body/div[@id=“name”] HTML下的body下的第一個id屬性為name的div
Xpath關注的點:
- xpath對普通字串無效
- xpath匹配不論是匹配到一個物件,還是多個,都以列表返回
- xpath返回的是xpath物件,如果需要呼叫匹配到的具體內容常用一下三個屬性
- text 返回文字
- attrib 返回屬性
- tag 返回標籤
當我們發現一下格式要注意
如果遇到以下問題,直接text匹配不到內容
<p>
Hello<span>while</span>
</p>
我寫一個xpath的例子
嘗試爬取代理ip
我們首先檢視網站結構
這個時候我們嘗試寫一下我們的lxml匹配規則
from lxml import etree
import requests
url = "http://www.xicidaili.com/"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36"
}
response = requests.get(url = url,headers = headers)
response_body = response.content.decode()
#print(response_body)
html = etree.HTML(response_body)
tr_list = html.xpath('//tr[@class="odd"]')
for tr in tr_list:
ip = tr.xpath("td[2]")[0].text
port = tr.xpath("td[3]")[0].text
address = tr.xpath("td[4]")[0].text
nm = tr.xpath("td[5]")[0].text
types = tr.xpath("td[6]")[0].text
time = tr.xpath("td[7]")[0].text
valid = tr.xpath("td[8]")[0].text
result_dict = {
"ip": ip,
"port": port,
"address": address,
"nm": nm,
"types": types,
"time": time,
"valid": valid
}
print(result_dict)
效果如下:
思考1:
完成正則例1的正則優化
思考2:
使用xpath匹配以下格式當中的hello
<p>
Hello<span>while</span>
</p>
思考3:
篩選出最新的5個透明的代理ip
用冒泡法對已有的ip按照存活的時間進行排序
請對以上3個問題進行思考,我將會在近期對以上被人進行更新,如果有好的答案,歡迎私信我
思考1中的優化:
res = re.findall(r"\d{17}.",content)
效果如下:
思考2:
from lxml import etree
text_str = '''
<p>
Hello<span>while</span>
</p>
'''
html = etree.HTML(text_str)
res = html.xpath('//p/text()')[0].strip()
print(res)
效果如下:
思考3:
import re
from lxml import etree
import requests
ip_list = []
all_list = []
url = "http://www.xicidaili.com/"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36"
}
response = requests.get(url = url,headers = headers)
response_body = response.content.decode()
#print(response_body)
html = etree.HTML(response_body)
tr_list = html.xpath('//tr[@class="odd"] | //tr[@class=""]')
for tr in tr_list:
ip = tr.xpath("td[2]")[0].text
port = tr.xpath("td[3]")[0].text
address = tr.xpath("td[4]")[0].text
nm = tr.xpath("td[5]")[0].text
types = tr.xpath("td[6]")[0].text
time = tr.xpath("td[7]")[0].text
valid = tr.xpath("td[8]")[0].text
result_dict = {
"ip": ip,
"port": port,
"address": address,
"nm": nm,
"types": types,
"time": time,
"valid": valid
}
all_list.append(result_dict)
niming = result_dict.get("nm")
if niming == "透明":
ip_list.append(result_dict)
# 利用冒泡對存活時間進行排序
def cunhuo(ls):
for j in range(len(ls)):
for i in range(len(ls)-1-j):
if int((re.findall(r'(\d+)',ls[i]['time']))[0]) < int((re.findall(r'(\d+)',ls[i+1]['time']))[0]):
ls[i],ls[i+1] = ls[i+1],ls[i]
for j in range(len(ls)):
for i in range(len(ls) - 1 - j):
if '分' in ls[i]['time']:
ls[i], ls[i + 1] = ls[i + 1], ls[i]
for j in range(len(ls)):
for i in range(len(ls) - 1 - j):
if '時' in ls[i]['time']:
ls[i], ls[i + 1] = ls[i + 1], ls[i]
for j in range(len(ls)):
for i in range(len(ls) - 1 - j):
if '天' in ls[i]['time']:
ls[i], ls[i + 1] = ls[i + 1], ls[i]
return ls
# 最新的五個透明代理ip
def mostNew(lt):
for j in range(len(lt)):
for i in range(len(lt)-1-j):
if int((re.findall(r'(\d+)',lt[i]['valid']))[0]) < int((re.findall(r'(\d+)',lt[i+1]['valid']))[0]):
lt[i],lt[i+1] = lt[i+1],lt[i]
for j in range(len(lt)):
for i in range(len(lt) - 1 - j):
if '不到' in lt[i]['valid']:
lt[i], lt[i + 1] = lt[i + 1], lt[i]
for j in range(len(lt)):
for i in range(len(lt) - 1 - j):
if '分' in lt[i]['valid']:
lt[i], lt[i + 1] = lt[i + 1], lt[i]
for j in range(len(lt)):
for i in range(len(lt) - 1 - j):
if '小時' in lt[i]['valid']:
lt[i], lt[i + 1] = lt[i + 1], lt[i]
for j in range(len(lt)):
for i in range(len(lt) - 1 - j):
if '天' in lt[i]['valid']:
lt[i], lt[i + 1] = lt[i + 1], lt[i]
for j in range(len(lt)):
for i in range(len(lt) - 1 - j):
if '月' in lt[i]['valid']:
lt[i], lt[i + 1] = lt[i + 1], lt[i]
for j in range(len(lt)):
for i in range(len(lt) - 1 - j):
if '年' in lt[i]['valid']:
lt[i], lt[i + 1] = lt[i + 1], lt[i]
return lt
if __name__ == "__main__":
print('==========' * 8)
print('最新5個透明代理ip如下:')
sort_list = mostNew(ip_list)
for i in range(1, 6):
print(sort_list[i])
print('=========='*8)
print('冒泡存活時間排序如下:')
statistics = cunhuo(all_list)
for i in statistics:
print(i)
效果如下:
以上的做法還可以繼續優化,存活時間還需要比較時間單位並不只是數字的大小,希望各位小夥伴們按照我的思路再思考思考