1. 程式人生 > >python爬取身份證資訊、爬取ip代理池

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

  1. 區別(是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步

  1. 構建HTML結構,將返回的字串從新轉換為HTML
  2. 進行匹配

      匹配的常用語法

     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關注的點:

  1. xpath對普通字串無效
  2. xpath匹配不論是匹配到一個物件,還是多個,都以列表返回
  3. xpath返回的是xpath物件,如果需要呼叫匹配到的具體內容常用一下三個屬性
  1. text 返回文字
  2. attrib 返回屬性
  3. tag 返回標籤

    當我們發現一下格式要注意

    如果遇到以下問題,直接text匹配不到內容

   <p>

         Hello<span>while</span>

   </p>

   我寫一個xpath的例子

              http://www.xicidaili.com/

              嘗試爬取代理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)

效果如下:

以上的做法還可以繼續優化,存活時間還需要比較時間單位並不只是數字的大小,希望各位小夥伴們按照我的思路再思考思考