xml是基于 libxml2解析庫的Python封裝。libxml2是使用C語言編寫的,解析速度很好,不過安裝起來稍微有點復雜。安裝說明可以參考(http: //Lxml.de/installation.html),在CentOS7上中文安裝說明(http://www.cjavapy.com/article/64/),使用lxml庫來解析網絡爬蟲抓取到的HTML是一種非常高效的方式。lxml的html模塊特別適合處理HTML內容,它可以快速解析大型HTML文件,并提供XPath和CSS選擇器來查詢和提取數據。
參考文檔:https://www.cjavapy.com/article/65/
從網絡上抓取到的html的內容,有可能都是標準寫法,標簽什么的都閉合,屬性也是標準寫法,但是有可能有的網站的程序員不專業,這樣抓到的html解析就有可能有問題,因此,解析時先將有可能不合法的html解析為統一的格式。避免為后續的解析造成困擾。
1、lxml.html
lxml.html是專門用于解析和處理HTML文檔的模塊。它基于lxml.etree,但是為HTML文檔的特點做了優化。lxml.html能夠處理不良形式的HTML代碼,這對于解析和爬取網頁尤其有用。
>>> import lxml.html
>>> broken_html = '<ul class="body"><li>header<li>item</ul>'
>>> tree = lxml.html.fromstring(broken_html) #解析html
>>> fixed_html = lxml.html.tostring(tree,pretty_print=True)
>>> print fixed_html
<ul class="body">
<li>header</li>
<li>item</li>
</ul>
2、lxml.etree
lxml.etree是lxml庫中用于處理XML文檔的模塊。它基于非常快的XML解析庫libxml2,提供了一個類似于標準庫xml.etree.ElementTreeAPI的接口,但是在性能和功能性方面要更加強大。lxml.etree支持XPath、XSLT、和Schema驗證等高級XML特性。
>>> import lxml.etree
>>> broken_html = '<ul class="body"><li>header<li>item</ul>'
>>> tree = lxml.etree.fromstring(broken_html) #解析html
>>> fixed_html = lxml.etree.tostring(tree,pretty_print=True)
>>> print fixed_html
<ul class="body">
<li>header</li>
<li>item</li>
</ul>
通過以上可以看出,lxml可以正確解析兩側缺失的括號,并閉合標簽,但不會額外增加<html>和<body>標簽。
若在html中找到我們想要的內容,用lxml有幾種不同的方法,XPath選擇器類似Beautiful Soup的find()方法。CSS選擇器用法和jQuery中的選擇器類似。兩種選擇器都可以用來查找文檔中的元素,但它們各有特點和適用場景。XPath是一種在XML文檔中查找信息的語言。它可以用來遍歷XML文檔的元素和屬性。CSS選擇器通常用于選擇和操作HTML文檔中的元素。
1、XPath選擇器(/單斜杠表示絕對查找,//雙斜杠表示相對查找)
from lxml import etree
source_html = """
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
"""
html = etree.HTML(source_html)
print(html)
result = etree.tostring(html)#會對的html標簽進行補全
print(result.decode("utf-8"))
輸出結果:
<Element html at 0x39e58f0>
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li></ul>
</div>
</body></html>
1)獲取某個標簽的內容(a標簽后不需要加斜杠,否則會報錯)
#第一種寫法
html = etree.HTML(source_html)
html_data = html.xpath('/html/body/div/ul/li/a')#絕對查找
#html_data = html.xpath('//li/a')#相對查找
print(html)
for i in html_data:
print(i.text)
輸出結果:
<Element html at 0x14fe6b8>
first item
second item
third item
fourth item
fifth item
#第二種寫法
#在要找的標簽后面加/text(),就是獲取標簽中的文本內容,結果中直接就是文本內容了,不用在通過text屬性獲取了。
html = etree.HTML(source_html)
html_data = html.xpath('/html/body/div/ul/li/a/text()')#絕對查找
#html_data = html.xpath('//li/a/text()')#相對查找
print(html)
for i in html_data:
print(i)
輸出結果:
<Element html at 0x128e3b7>
first item
second item
third item
fourth item
fifth item
2)獲取a標簽下的屬性
html = etree.HTML(source_html)
html_data = html.xpath('//li/a/@href') #相對查找
#html_data = html.xpath('/html/body/div/ul/li/a/@href') #絕對查找
for i in html_data:
print(i)
輸出結果:
link1.html
link2.html
link3.html
link4.html
link5.html
3)查找a標簽屬性等于link2.html的內容
html = etree.HTML(source_html)
html_data = html.xpath('/html/body/div/ul/li/a[@href="link2.html"]/text()')絕對查找
#html_data = html.xpath('//li/a[@href="link2.html"]/text()')#相對查找
print(html_data)
for i in html_data:
print(i)
輸出結果:
['second item']
second item
4)查找最后一個li標簽里的a標簽的href屬性
html = etree.HTML(source_html)
html_data = html.xpath('//li[last()]/a/text()')
print(html_data)
for i in html_data:
print(i)
輸出結果:
['fifth item']
fifth item
5)查找倒數第二個li標簽里a標簽的href屬性
html = etree.HTML(source_html)
html_data = html.xpath('//li[last()-1]/a/text()')
print(html_data)
for i in html_data:
print(i)
輸出結果:
['fourth item']
fourth item
6)查找某個標簽id屬性值等于value的標簽
//*[@id="value"]
7)使用chrome瀏覽器提取某個標簽的XPath
2、CSS選擇器(基本上和jQuery選擇器用法一樣)
選擇器 | 描述 |
* | 選擇所有標簽 |
a | 選擇<a>標簽 |
.link | 選擇所有class = 'link'的元素 |
a.link | 選擇class = 'link'的<a>標簽 |
a#home | 選擇id = 'home'的<a>標簽 |
a > span | 選擇父元素為<a>標簽的所有<span>子標簽 |
a span | 選擇<a>標簽內部的所有<span>標簽 |
使用示例:
>>> html = """<div>
<tr id="places_area_row" class="body">
<td>header</td>
<td class="w2p_fw">item1</td>
<td class="w2p_fw">item2</td>
<td class="w2p_fw">item3</td>
<td><tr><td class="w2p_fw">header</td>
<td class="w2p_fw">item4</td>
<td class="w2p_fw">item5</td>
<td class="w2p_fw">item6</td></tr></td>
</tr>
</div>"""
>>> tree = lxml.html.fromstring(html)
>>> td = tree.cssselect('tr#places_area_row > td.w2p_fw')[0]
>>> htmlText = td.text_content()
>>> print htmlText
item1
參考文檔:https://www.cjavapy.com/article/65/
?
深入理解C語言:實用技巧與案例分析
## 一、引言
C語言作為一門古老而強大的編程語言,其深層次的理解和實際運用對于程序員至關重要。本文將介紹一些實用技巧和通過案例分析來幫助讀者深入理解C語言的精髓。
我整理了一些資料https://m.hqyjai.net/emb_study_blue_short.html?xt=yj
## 二、C語言實用技巧
### 1. 指針技巧
指針是C語言中獨特且重要的概念,掌握指針技巧能夠讓程序更高效地操作內存,包括指針運算、指針數組等應用。
### 2. 宏定義技巧
宏定義是C語言中的一種預處理指令,通過宏定義可以簡化代碼、提高可讀性,同時也可以實現一些高級的功能,如條件編譯、函數宏等。
### 3. 內聯函數技巧
內聯函數是一種高效的函數調用方式,通過內聯函數可以減少函數調用的開銷,提高程序的執行效率,了解內聯函數的使用場景和注意事項非常重要。
## 三、C語言案例分析
### 1. 數據結構實現
通過案例分析不同數據結構的實現,如鏈表、棧、隊列等,可以幫助讀者理解數據結構在C語言中的具體應用和實現方式。
### 2. 算法優化實例
通過實際的算法優化案例,包括排序算法、查找算法等,展示如何在C語言中利用技巧和優化策略提升算法的效率和性能。
### 3. 實戰項目展示
通過展示一些實際的C語言項目,如簡單的文件處理、網絡編程、圖形界面等,讓讀者從實際項目中學習C語言的應用和實踐技巧。
我整理了一些資料https://m.hqyjai.net/emb_study_blue_short.html?xt=yj
## 四、結語
通過本文的介紹和案例分析,讀者將更深入地理解C語言的實用技巧和應用場景,希望能夠為讀者在C語言編程的道路上提供一些啟發和幫助。
以上是對《深入理解C語言:實用技巧與案例分析》的小點論述,希望能夠帶給您有益的啟示和知識。
tmlAgilityPack 是一個 HTML 解析庫,用于 .NET 平臺。它允許開發者以類似于解析 XML 的方式,輕松地解析和操作 HTML 文檔。這個庫特別適合處理非標準的 HTML,例如那些格式不正確或包含錯誤的 HTML 文檔。
從原理上說,解析是一個 CPU 密集型操作。在計算資源充裕的情況下,使用多線程并行可以加快處理速度。
以下代碼展示了兩個場景:
使用一個線程解析 1000 個頁面
使用 8 個線程解析 1000 個頁面(總量 1000 個,測試機器上的 CPU 有 8 個內核)。
string html = File.ReadAllText("PATH");
//One thread
for (int i = 0; i < 1000; i++)
new HtmlDocument().LoadHtml(html);
//Several threads
Parallel.For(0, 1000, (int i) => new HtmlDocument().LoadHtml(html));
然而實際的情況是:盡管多線程版本消耗了 2 ~ 3 倍的 CPU,但所花費的時間大致相同。而且 CPU 占用率一直維持在 30% 以下。即便更換了要處理的頁面,或者內核數量更多的電腦,情況都差不多。
開啟更多的線程并不會提升處理的速度,這讓我開始懷疑是不是存在鎖的問題。遺憾的是沒有在源代碼中找到 lock ,但是發現了一個 Issues:
https://github.com/zzzprojects/html-agility-pack/issues/191
在使用 Profiler 工具對多線程程序進行分析之后,發現程序可能存在內存瓶頸。根據他的觀察,有大約 50% 的 CPU 時間耗費在了內存分配上。
這和使用的 GC 類型有關,向 App.config 增加以下代碼可以解決該問題:
<runtime>
<gcServer enabled="true"/>
<gcConcurrent enabled="false" />
</runtime>
我的程序是一個使用 .NET 8.0 框架的控制臺,增加 App.config 文件之后并沒有效果。于是,我找到了微軟的官方文檔:
https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/garbage-collector
根據文檔所述,可以通過環境變量、runtimeconfig.json 文件或項目文件來指定程序使用 Server 版本。我選擇修改項目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
</Project>
問題得以解決:處理速度快了不少,CPU 占用維持在了 70% 左右。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。