python學習之網絡數據解析

正則表達式

實際上爬蟲一共就四個主要步驟:

  1. 明確目標 (要知道你準備在哪個範圍或者網站去搜索)
  2. 爬 (將所有的網站的內容全部爬下來)
  3. 取 (去掉對我們沒用處的數據)
  4. 處理數據(按照我們想要的方式存儲和使用)
    正則表達式,又稱規則表達式,通常被用來檢索、替換那些符合某個模式(規則)的文本。
    python學習之網絡數據解析
    python學習之網絡數據解析
    正則表達式匹配規則
    python學習之網絡數據解析
    python學習之網絡數據解析
    python學習之網絡數據解析
    python學習之網絡數據解析
    python學習之網絡數據解析

    re 模塊一般使用步驟

  5. 使用 compile() 函數將正則表達式的字符串形式編譯爲一個 Pattern 對象
    注意: re對特殊字符進行轉義,如果使用原始字符串,只需加一個 r 前綴
  6. 通過 Pattern 對象對文本進行匹配查找,獲得匹配結果,一個 Match 對象。
  7. 使用 Match 對象提供的屬性和方法獲得信息,根據需要進行其他的操作
    python學習之網絡數據解析
import re

text = """
2020-10-10
2020-11-11
2030/12/12
"""

#1. 使用 compile() 函數將正則表達式的字符串形式編譯爲一個 Pattern 對象
#注意: re對特殊字符進行轉義,如果使用原始字符串,只需加一個 r 前綴
#pattern = re.compile(r'\d{4}-\d{1,2}-\d{1,2}')    # 2020-4-11, 無分組的規則
#pattern = re.compile(r'(\d{4})-(\d{1,2})-(\d{1,2})')    # 2020-4-11, 有分組的規則
pattern = re.compile(r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})')  # 2020-4-11, 有命名分組的規則
#  2. 通過 Pattern 對象對文本進行匹配查找,獲得匹配結果,一個 Match 對象。
# search從給定的字符串中尋找一個符合規則的字符串, 只返回一個
result = re.search(pattern, text)
print(result)
# 3. 使用 Match 對象提供的屬性和方法獲得信息,根據需要進行其他的操作
print("匹配到的信息:", result.group())  # 返回的是匹配到的文本信息
print("匹配到的信息:", result.groups())  # 返回的是位置分組, ('2020', '10', '10')
print("匹配到的信息:", result.groupdict())  # 返回的是關鍵字分組.{'year': '2020', 'month': '10', 'day': '10'}

Pattern 對象

正則表達式編譯成 Pattern 對象, 可以利用 pattern 的一系列方法對文本進行匹配查找
了。
Pattern 對象的一些常用方法主要有:
• match 方法:從起始位置開始查找,一次匹配
• search 方法:從任何位置開始查找,一次匹配
• findall 方法:全部匹配,返回列表
• finditer 方法:全部匹配,返回迭代器
• split 方法:分割字符串,返回列表
• sub 方法:替換

match 方法

match 方法用於查找字符串的頭部(也可以指定起始位置),它是一次匹配,只要
找到了一個匹配的結果就返回, 而不是查找所有匹配的結果。它的一般使用形式如下:
python學習之網絡數據解析
• string 待匹配的字符串
• pos 字符串的起始位置, 默認值是 0
• endpos 字符串的終點位置, 默認值是 len (字符串長度)

Match 對象

• group([group1, ...]) 方法用於獲得一個或多個分組匹配的字符串,當要獲得整個匹配的子串
時,可直接使用 group() 或 group(0);
• start([group]) 方法用於獲取分組匹配的子串在整個字符串中的起始位置(子串第一個字符的
索引),參數默認 值爲 0;
• end([group]) 方法用於獲取分組匹配的子串在整個字符串中的結束位置(子串最後一個字符
的索引+1),參數 默認值爲 0;
• span([group]) 方法返回 (start(group), end(group))

search 方法

search 方法用於查找字符串的任何位置,它也是一次匹配,只要找到了一個匹配的
結果就返回,而不是查找所有 匹配的結果,它的一般使用形式如下:
python學習之網絡數據解析
當匹配成功時,返回一個 Match 對象,如果沒有匹配上,則返回 None。
findall 方法與finditer 方法
findall 方法搜索整個字符串,獲得所有匹配的結果。使用形式如
python學習之網絡數據解析
finditer 方法的行爲跟 findall 的行爲類似,也是搜索整個字符串,獲得
所有匹配的結果。但它返回一個順序訪問每 一個匹配結果(Match 對象)
的迭代器。

split 方法

split 方法按照能夠匹配的子串將字符串分割後返回列表,它的使用形式如下:
python學習之網絡數據解析
• maxsplit 指定最大分割次數,不指定將全部分割
python學習之網絡數據解析

sub 方法

sub 方法用於替換。它的使用形式如下:
python學習之網絡數據解析

import  re

#****************************split***************************
#text = '1+2*4+8-9/10'
##字符串方法: '172.25.254.250'.split('.')   => ['172', '25', '254', '250']
#pattern = re.compile(r'\+|-|\*|/')
##將字符串根據+或者-或者*或者/進行切割.
#result = re.split(pattern, text)
#print(result)

#***********************sub**************************************
def repl_string(matchObj):
    # matchObj方法: group, groups, groupdict
    items = matchObj.groups()
    #print("匹配到的分組內容: ", items)   # ('2019', '10', '10')
    return  "-".join(items)

#2019/10/10 ====> 2019-10-10
text = "2019/10/10 2020/12/12 2019-12-10  2020-11-10"
pattern = re.compile(r'(\d{4})/(\d{1,2})/(\d{1,2})')  # 注意: 正則規則裏面不要隨意空格
#將所有符合條件的信息替換成'2019-10-10'
#result = re.sub(pattern, '2019-10-10', text)
#將所有符合條件的信息替換成'year-month-day'
result = re.sub(pattern, repl_string, text)
print(result)

• repl 可以是字符串也可以是一個函數:
1). 如果 repl 是字符串,則會使用 repl 去替換字符串每一個匹配的子串,並返回替換
後的字符串,另外,repl 還 可以使用 id 的形式來引用分組,但不能使用編號 0;
2). 如果 repl 是函數,這個方法應當只接受一個參數(Match 對象),並返回一個字
符串用於替換(返回的字符 串中不能再引用分組)。
• count 用於指定最多替換次數,不指定時全部替換。
在某些情況下,我們想匹配文本中的漢字,有一點需要注意的是,中文的 unicode 編碼
範圍 主要在[u4e00-u9fa5],這裏說主要是因爲這個範圍並不完整,比如沒有包括全角(中文)標點,不過,在大部分情況下,應該是 夠用的

貪婪模式與非貪婪模式:abbbc

  1. 貪婪模式:在整個表達式匹配成功的前提下,儘可能多的匹配 ( );
    使用貪婪的數量詞的正則表達式 ab
    ,匹配結果: abbb。
    • 決定了儘可能多匹配 b,所以a後面所有的 b 都出現了。
  2. 非貪婪模式:在整個表達式匹配成功的前提下,儘可能少的匹配 ( ? );
    使用非貪婪的數量詞的正則表達式 ab? ,匹配結果: a。
    即使前面有
    ,但是 ? 決定了儘可能少匹配 b,所以沒有 b。
  3. Python裏數量詞默認是貪婪的。
常用的正則常量:
    "ASCII": 'A'
    "IGNORECASE": 'I'
    "MULTILINE":'M'
    "DOTALL":'S'

import  re

#********************************   1. re.ASCII *****************************
#text = "正則表達式re模塊是python中的內置modelue."
##匹配所有的\w+(字母數字下劃線, 默認也匹配中文), 不想匹配中文時,指定flags=re.A
#result = re.findall(r'\w+', string=text, flags=re.A)
#print(result)

#********************************   2. re.IGNORECASE *****************************
#text = 'hello world heLLo westos Hello python'
##匹配所有he\w+o, 忽略大小寫, re.I
#result = re.findall(r'he\w+o', text, re.I)
#print(result)           # ['hello', 'heLLo', 'Hello']

##********************************   3. re.S *****************************
#text = 'hello \n world'
#result = re.findall(r'^he.*?ld$', text, re.S)
#print(result)

##************************匹配中文**********************
#pattern = r'[\u4e00-\u9fa5]'
#text = "正則表達式re模塊是python中的內置modelue."
#result = re.findall(pattern, text)
#print(result)

XPath庫

lxml是python的一個解析庫,支持HTML和XML的解析,支持XPath解析方式,而且解析
效率非常高。
XPath (XML Path Language) 是一門在 xml文檔中查找信息的語言,可用來在 xml
/html文檔中對元素和屬性進行遍歷。
謂語(Predicates)
謂語用來查找某個特定的節點或者包含某個指定的值的節點,被嵌在方括號中。
python學習之網絡數據解析
XPath常用規則彙總
python學習之網絡數據解析

基於requests和Xpath的TIOBE編程語言排行榜定向爬蟲.py

import csv

import requests
from colorama import Fore
from fake_useragent import UserAgent
from lxml import etree
from requests import HTTPError

def download_page(url, parmas=None):
    """
    根據url地址下載html頁面
    :param url:
    :param parmas:
    :return: str
    """
    try:
        ua = UserAgent()
        headers = {
            'User-Agent': ua.random,
        }
        #請求https協議的時候, 回遇到報錯: SSLError
        #verify=Flase不驗證證書
        response = requests.get(url, params=parmas, headers=headers)
    except  HTTPError as e:
        print(Fore.RED + '[-] 爬取網站%s失敗: %s' % (url, str(e)))
        return None
    else:
        # content返回的是bytes類型, text返回字符串類型
        return response.text

def parse_html(html):
    """
    編程語言的去年名次、今年名次、編程語言名稱、評級Rating和變化率Change等信息。
    :param html:
    :return:
    """
    #1). 通過lxml解析器解析頁面信息, 返回Element對象
    html = etree.HTML(html)
    #2). 根據Xpath路徑尋找語法獲取編程語言相關信息
    #獲取每一個編程語言的Element對象
    #<table id="top20" class="table table-striped table-top20">
    languages = html.xpath('//table[@id="top20"]/tbody/tr')

    # 依次獲取每個語言的去年名次、今年名次、編程語言名稱、評級Rating和變化率Change等信息。
    for language in languages:
        # 注意: Xpath裏面進行索引時,從1開始
        now_rank = language.xpath('./td[1]/text()')[0]
        last_rank = language.xpath('./td[2]/text()')[0]
        name = language.xpath('./td[4]/text()')[0]
        rating = language.xpath('./td[5]/text()')[0]
        change = language.xpath('./td[6]/text()')[0]
        yield {
            'now_rank': now_rank,
            'last_rank': last_rank,
            'name': name,
            'rating': rating,
            'change': change
        }

def save_to_csv(data, filename):
    # 1). data是yield返回的字典對象
    # 2). 以追加的方式打開文件並寫入
    # 3). 文件的編碼格式是utf-8
    # 4). 默認csv文件寫入會有空行, newline=''
    with open(filename, 'a', encoding='utf-8', newline='') as f:
        csv_writer = csv.DictWriter(f, ['now_rank', 'last_rank', 'name', 'rating', 'change'])
        # 寫入csv文件的表頭
        # csv_writer.writeheader()
        csv_writer.writerow(data)

def get_one_page(page=1):
    url = 'https://www.tiobe.com/tiobe-index/'
    filename = 'tiobe.csv'
    html = download_page(url)
    items = parse_html(html)
    for item in items:
        save_to_csv(item, filename)
    print(Fore.GREEN + '[+] 寫入文件%s成功' %(filename))

if __name__ == '__main__':
    get_one_page()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章