内容简介:数据处理的数据集并非立即可得,有时我们需要自己收集�数据,对很多研究领域,网页内容是一个重要的数据源。
数据处理的数据集并非立即可得,有时我们需要自己收集�数据,对很多研究领域,网页内容是一个重要的数据源。
查阅网页内容
下面是一个简单的网页,几乎所有的网页都可以查看源代码(一般是右键——点击查看源代码)。
<!DOCTYPE html> <html> <head> <title>Simple page</title> </head> <body> <h1>Heading 1</h1> <p>This is a paragraph.</p> </body> </html>
网页源码其实是HTML(Hyper Text Markup Language)文件。HTML是互联网使用最广泛的语言,它描述了网页的布局排版和内容,浏览器则根据Web标准将代码渲染到网页上。
尽管上面的网页代码很简单,但实际上认真点就会发现HTML是一些标签的嵌套结构,这些标签包括: <html>
、 <title>
、 <body>
、 <h1>
和 <p>
,现代浏览器根据HTML的第一行决定使用哪种标准进行网页渲染。上面例子使用的是HTML 5。
网页的这些标签并不是随意命名的,也不能任意包含其他标签,每个标签对浏览器都有特殊含义,且只允许包含一部分特定标签或不允许包含任何标签。
标签 <html>
是所有HTML的根元素。HTML通常也包括 <head>
和 <body>
。其中 <head>
通常包含 <title>
,展示在标题栏,包含浏览标签和网页元数据。而 <body>
则在网页内容和排版方面起主要作用。
在 <body>
标签中,标签可以更自由地嵌套,最简单的一个网页可以只包含一级标题( <h1>
)和一个段落( <p>
)。
关于表格:
<table> <tr> <th> <td>
一些其他标签:
<div> <ul> <li> <span>
HTML有一个属性,称为style,用于定义这些元素的样式外观。
HTML使用CSS可以避免冗长的样式定义。
每个CSS元素都包含一个CSS选择器用来匹配HTML元素和样式以便渲染应用。CSS选择器不仅用于应用样式,也常用于提取网页内容,以便我们感兴趣的HTML元素可以被正确匹配,这正是网络爬虫的底层技术。
对于网络爬虫,使用下面例子展示最常见的CSS选择器
语法 | 匹配 |
---|---|
*
|
All elements |
h1,h2,h3
|
<h1>,<h2>,<h3>
|
#table
|
<* id="table">
|
.product-list
|
<* class="product-list">
|
div#container
|
<div id="container">
|
div a
|
<div><a>and<div><p><a>
|
div >a
|
<div><a>but not<div><p><a>
|
div >a.new
|
<div><a class="new">
|
ul > li:first-child
|
First <li> in <ul>
|
ul > li:last-child
|
Last <li> in <ul>
|
ul > li:nth-child(3)
|
3rd <li> in <ul>
|
p + *
|
Next element of <p>
|
img[title]
|
<img> with title attribute
|
table[border=l]
|
<table border="l">
|
使用CSS选择器从网页中提取数据
R里面爬虫最简单易用的扩展包是 rvest
,安装:
install.packages("rvest")
下面我们读取一个简单表格HTML数据并提取表格:
library(rvest) #> 载入需要的程辑包:xml2 single_table_page = read_html("../../R/learningR_data/single-table.html") single_table_page #> {xml_document} #> <html> #> [1] <head>\n<meta http-equiv="Content-Type" content="text/html; charset= ... #> [2] <body>\n <p>The following is a table</p>\n <table id="table1" bord ...
single_table_page
是HTML解析文档,是HTML节点的嵌套数据结构。
使用 rvest
函数从网页上爬取信息的典型过程是这样的。首先,定位需要从中提取数据的HTML节点。然后使用CSS选择器或者XPath表达式筛选HTML节点,从而选择需要的节点,剔除不需要的节点。最后,对已解析的网页使用合适的选择器,用 html_nodes()
提取节点子集,用 html_attrs()
提取属性,用 html_text()
提取文本。
rvest
包提供了一些简单函数可直接用于提取数据并返回一个数据框,例如提取网页中的 <table>
元素,直接使用 html_table()
:
html_table(single_table_page) #> [[1]] #> Name Age #> 1 Jenny 18 #> 2 James 19
为提取第一个元素,我们先选择第一个节点,然后再提取表格:
html_table(html_node(single_table_page, "table")) #> Name Age #> 1 Jenny 18 #> 2 James 19
连续的操作可以使用管道:
single_table_page %>% html_node("table") %>% html_table() #> Name Age #> 1 Jenny 18 #> 2 James 19
现在我们读取一个产品信息网页,然后用 html_nodes()
匹配 <span class="name">
节点:
products_page = read_html("../../R/learningR_data/products.html") products_page %>% html_nodes(".product-list li .name") #> {xml_nodeset (3)} #> [1] <span class="name">Product-A</span> #> [2] <span class="name">Product-B</span> #> [3] <span class="name">Product-C</span>
这里我们选择的是product-list类的 <li>
标签下name类的节点,因此使用 .product-list li .name
,如果对符号不熟悉,需要详细记忆CSS表。
之后提取内容:
products_page %>% html_nodes(".product-list li .name") %>% html_text() #> [1] "Product-A" "Product-B" "Product-C"
类似的可以提取产品价格:
products_page %>% html_nodes(".product-list li .price") %>% html_text() #> [1] "$199.95" "$129.95" "$99.95"
使用XPath选择器
一般来说,CSS选择器足够满足绝大多数HTML节点匹配的需要。但需要根据某些特殊条件选择节点时,需要更强大的技术。
请看下面新的产品信息网页的源代码:
<!DOCTYPE html> <html> <head> <title>New Products</title> <style> p { margin: 2px; } .product-list { width: 80%; } .product-list ul { padding-left: 8px; } .product-list ul li { padding-left: 2px; list-style: none; } .product-list > ul > li { margin-top: 16px; list-style: none; } .product-list .name { font-weight: bold; font-size: 1.25em; } .product-list .price { color: green; } .product-list .info { background-color: #efefef; border-radius: 4px; } .info-key { font-weight: bold; } .info-value { } .unit { padding-left: 4px; color: #818181; } .bordered { border: 1px gray dashed; border-radius: 4px; } </style> </head> <body> <h1>New Products</h1> <p>The following is a list of products</p> <div id="list" class="product-list"> <ul> <li> <span class="name">Product-A</span> <span class="price">$199.95</span> <div class="info bordered"> <p>Description for Product-A</p> <ul> <li><span class="info-key">Quality</span> <span class="info-value">Good</span></li> <li><span class="info-key">Duration</span> <span class="info-value">5</span><span class="unit">years</span></li> </ul> </div> </li> <li class="selected"> <span class="name">Product-B</span> <span class="price">$129.95</span> <div class="info"> <p>Description for Product-B</p> <ul> <li><span class="info-key">Quality</span> <span class="info-value">Medium</span></li> <li><span class="info-key">Duration</span> <span class="info-value">2</span><span class="unit">years</span></li> </ul> </div> </li> <li> <span class="name">Product-C</span> <span class="price">$99.95</span> <div class="info"> <p>Description for Product-C</p> <ul> <li><span class="info-key">Quality</span> <span class="info-value">Good</span></li> <li><span class="info-key">Duration</span> <span class="info-value">4</span><span class="unit">years</span></li> </ul> </div> </li> </ul> </div> <p>All products are available for sale!</p> </body> </html>
我们先读入网页:
page = read_html("../../R/learningR_data/new-products.html")
在继续之前,我们需要了解下XML,编写良好且组织规范的HTML文档可以被看做XML文档的一个特例,与HTML不同,XML允许任意的标签和属性。下面是一个简单示例:
<?xml version = "1.0"?> <root> <product id = "1"> <name>Product-A</name> <price>$199.95</price> </product> <product id = "2"> <name>Product-B</name> <price>$129.95</price> </product> </root>
XPath专门用于提取XML文档中的数据, html_nodes()
支持XPath表达式,可以通过参数 xpath=
实现。
CSS选择器会匹配所有子层级的节点,而XPath表达式中,标签 //
和 /
匹配不同的节点,即 //
标签引用所有子层级的节点,而 /
标签只引用第1个子层级的 <tag>
节点。
下面是一些用法:
-
选择所有
<p>
节点
page %>% html_nodes(xpath = "//p") #> {xml_nodeset (5)} #> [1] <p>The following is a list of products</p> #> [2] <p>Description for Product-A</p> #> [3] <p>Description for Product-B</p> #> [4] <p>Description for Product-C</p> #> [5] <p>All products are available for sale!</p>
选择所有具有class属性的 <li>
节点:
page %>% html_nodes(xpath = "//li[@class]") #> {xml_nodeset (1)} #> [1] <li class="selected">\n <span class="name">Product-B</span>\n ...
选择 <div id = "list"><ul>
节点所有 <li>
子节点:
page %>% html_nodes(xpath = "//div[@id = 'list']/ul/li") #> {xml_nodeset (3)} #> [1] <li>\n <span class="name">Product-A</span>\n <span cla ... #> [2] <li class="selected">\n <span class="name">Product-B</span>\n ... #> [3] <li>\n <span class="name">Product-C</span>\n <span cla ...
选择所有嵌套于 <div id = "list">
中 <li>
标签下的 <span class = "name">
子节点:
page %>% html_nodes(xpath = "//div[@id = 'list']//li/span[@class='name']") #> {xml_nodeset (3)} #> [1] <span class="name">Product-A</span> #> [2] <span class="name">Product-B</span> #> [3] <span class="name">Product-C</span>
选择嵌套于 <li class = "selected">中<span class = "name">
子节点。
page %>% html_nodes(xpath = "//li[@class='selected']/span[@class = 'name']") #> {xml_nodeset (1)} #> [1] <span class="name">Product-B</span>
下面例子就不能用等效CSS来实现了:
-
选择所有包含
<p>
子节点的<div>
节点:
page %>% html_nodes(xpath = "//div[p]") #> {xml_nodeset (3)} #> [1] <div class="info bordered">\n <p>Description for Product-A< ... #> [2] <div class="info">\n <p>Description for Product-B</p>\n ... #> [3] <div class="info">\n <p>Description for Product-C</p>\n ...
-
选择所有的
<span class = "info-value">Good</span>
page %>% html_nodes(xpath = "//span[@class ='info-value' and text() = 'Good']") #> {xml_nodeset (2)} #> [1] <span class="info-value">Good</span> #> [2] <span class="info-value">Good</span>
XPath非常灵活,在匹配节点方面是强大的工具。
更多匹配内容可以阅读W3School。
以上所述就是小编给大家介绍的《R-网页爬虫:初识》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。