HTML Tag Selector標籤選擇器設計(手稿PFC020512)

(手稿PFC020512

用慣了xpath、scrapy或jsoup這類HTML 文檔解析器,今天決定試試實現其tag selector標籤選擇器。

HTML是一個規範的文檔。一般來說,HTML文檔是對稱閉合的,跟XML文檔很相似,但不是嚴格的。HTML tag標籤一般由“<”、“>”包圍,標籤開始符基本要素爲左右尖括號界定符、tag標籤名、tag標籤屬性和tag標籤屬性值,表達式爲:<[tag name] [tag attribute name]=”[tag attribute value]”>,標籤結束符表達式爲:</[tag name]>。其中,tag標籤屬性和值爲非必要。標籤屬性和值的賦值表達式爲:[屬性]=”[值]”或[屬性]=[值]兩種,一般推薦前者的使用方法。屬性賦值表達式之間使用空格分隔。

HTML標籤具有規範的屬性,也可以自定義屬性。自定義屬性可以保存一定的數據,不能被標準的HTML解釋器識別。一般情況下,優先考慮標準HTML的實現。

HTML文檔解析器本質上是語法樹的一種實現,簡單來說,根據特定的標籤詞彙和語法規則實現對HTML文檔的解析處理。底層的語法樹一般是使用類似於遞歸的處理方法。像函數遞歸和快速排序都是很有意思的語法規則設計。都是使用簡短的語句實現人的智慧精華。說了這麼多,下面來試試從高級語言層面實現標籤選擇器。這裏筆者主要是通過正則表達式來完成其實現。

標籤選擇器最基本的是標籤的識別。前面提到,標籤開始符和結束符的表達式分別爲:<[tag]>、</[tag]>,[tag]爲由英文字母組成的標籤名。對應正則表達式:

<python>

tag_start_pattern=’<tag>’

tag_end_pattern=’</tag>’

</python>

標籤屬性賦值表達式爲:[ ][attribute]=”[value]”,對應正則表達式:

<python>
tag_attribute_pattern=’[ ][attribute][=][“][value][“]’

</python>

應用模式除包含上述表達式外,還需進行標籤最小配對或標籤對稱等優化。

以下是實現代碼的草稿:

<python>

# -*- coding: UTF-8 -*-

# !/usr/bin/env python

'''

author: MRN6

blog: [email protected]

'''

import re


#定義path規則

def qpath(path=None, html=None):

    if path is None or html is None:

        return  []

    rules=path.split("//")

    matches=""

    for rule in rules:

        if len(rule.strip())<1:

            continue

        ruledatas=rule.split(':')

        tag=ruledatas[0]

        attributedatas=ruledatas[1].split('=')

        attribute=attributedatas[0]

        value=attributedatas[1]

        print('<'+tag+' '+attribute+'="'+value+'"')

        rules=len(ruledatas)

        if rules==2:
   
            matches=re.findall('(<'+tag+'[^<>]*'+attribute+'="'+value+'[^"]*"[^<>]*>((?!<'+tag+'[^<>]*'+attribute+'="'+value+'"[^<>]*>).)*</'+tag+'>$)', html, re.M|re.S|re.I)

        elif rules==3 and ruledatas[2]=='END':

            matches=re.findall('(<'+tag+'[^<>]*'+attribute+'="'+value+'[^"]*"[^<>]*>((?!</'+tag+'>).)*</'+tag+'>$)', html, re.M|re.S|re.I)

            #注:參考https://blog.csdn.net/iteye_13785/article/details/82638686

        #檢查標籤對稱問題

        if len(matches)>0:

            for match in matches:

                smatches=re.findall('<'+tag, match[0], re.M|re.S|re.I)

                ematches=re.findall('</'+tag+'>', match[0], re.M|re.S|re.I)

                slen=len(smatches)

                elen=len(ematches)

                if slen!=elen:

                    print(match[0]+' greedy match: '+str(slen)+'-'+str(elen))

    return matches



html='''

<!DOCTYPE html>

<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">

<title>標題</title>

</head>

<body>

    <div id="root">

        <div class="content-item first">

            <div class="content-title">title1</div>

            <div class="content-body">content1</div>

        </div>

        <div class="content-item">

            <div class="content-title">title_2</div>

            <div class="content-body">content2</div>

        </div>

        <div>&nbsp;</div>

        <div class="content-item">

            <div class="content-title">title3_</div>

            <div class="content-body">content3</div>

        </div>

</div>

<div>&nbsp;</div>

</body>

</html>

'''

mypath="//div:id=root//div:class=content-item"

mypath2="//div:id=root//div:class=content-item//div:class=content-title:END"

results=qpath(mypath, html)

print(len(results))

for result in results:

    print(result)



results2=qpath(mypath2, html)

print(len(results2))

for result in results2:

    print(result)

</python>

 

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