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小时内与您取得联系。