R:xml2提取的节点数多于预期

时间:2017-01-08 12:29:17

标签: r web-scraping libxml2 rvest xml2

我不明白为什么这段代码

library(rvest)
u <- "http://alistapart.com/article/daemonskin"
h <- read_html(u)
html_nodes(h, "div.main-content[itemprop='articleBody'] a") %>%
  html_attr("href")

匹配超出目标<div>元素范围的许多网址。

如果您查看target page的HTML源代码:

  • 只有一个<div>符合我的查询。它从第177行开始。
  • <div>在第396行停止。
  • 上面代码中html_nodes返回的许多网址都是从该行<div>之外的节点中提取的。

注意:您可能会注意到,在HTML的第242行,存在错误的</div元素。但是,修复它似乎无法解决问题。

我想这个问题与xml2(即libxml2)解析代码的方式有关。

还有其他想法吗?

1 个答案:

答案 0 :(得分:1)

嗯,问题是网站上制作不当,不合规的HTML,它在这方面比其他所有人都更加聪明。

当你这样做时:

library(rvest)
library(purrr)

URL <- "http://alistapart.com/article/daemonskin"

read_html(URL) %>%
  html_nodes("div.main-content[itemprop='articleBody'] a") %>%
  html_attr("href") %>%
  str()
##  chr [1:74] "#comments" ...

基础libxml2库是&#34;修复&#34;轻微的HTML(XML)错误,并有自己的做事方式。由于解析器&#34;固定&#34;的方式,这种方式会导致更多元素置于特定<div>您的目标之下。 HTML。

您可以看到真实浏览器的结果与我们可以用硒模拟的结果的区别:

注意:我在R

之外的webdriver模式下启动了phantomjs
library(seleniumPipes)

rd <- remoteDr(browserName = "phantomjs", port = 8910)
rd %>% go(URL)

当你这样做时,它的幻像(webkit,真的)将它自己的基于浏览器的HTML解析器修复方法应用于它收到的HTML(并且,它还增加或减少基于页面加载时任何javascript触发器的节点。)

当您使用等效的document.querySelectorAll()来检索您获得的节点34时(这也是我在开发人员工具控制台中在Chrome中获得的):

rd %>%
  findElements("css", "div.main-content[itemprop='articleBody'] a") %>%
  map_chr(getElementAttribute, "href") %>%
  str()
##  chr [1:34] "http://alistapart.com/article/daemonskin#comments" ...

请注意,如果您决定执行我通常所做的操作并使用getPageSource()通过rvest / xml2功能进行所有选择/提取,那么您将获得不同的功能结果,因为它从虚拟浏览器中提取当前的HTML页面并将其传递给read_html()libxml2已经rd %>% go(URL) %>% getPageSource() %>% html_nodes("div.main-content[itemprop='articleBody'] a") %>% html_attr("href") %>% str() ## chr [1:32] "#comments" ... 对理论上已经清理过的webkit应用了一些额外的修复:

<!-- navbar-->
<nav class="navbar navbar-default">
    <div class="container-fluid">
        <a href="#" class="navbar-header navbar-brand">MYSITE</a>
        <ul class="nav navbar-nav">

        <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Tags <span class="caret"></span></a>

            <ul class="dropdown-menu">
                <li><a href="#">menu1</a></li>
                <li><a href="#">menu2</a></li>
                <li><a href="#">menu3</a></li>
                <li><a href="#">menu4</a></li>
                <li><a href="#">menu5</a></li>
                <li><a href="#">menu6</a></li>
                <li><a href="#">menu7</a></li>
                <li><a href="#">menu8</a></li>
                <li><a href="#">menu9</a></li>
                <li><a href="#">menu10</a></li>
                <li><a href="#">menu11</a></li>
                <li><a href="#">menu12</a></li>
                <li><a href="#">menu13</a></li>
                <li><a href="#">menu14</a></li>
                <li><a href="#">menu15</a></li>
                <li><a href="#">menu16</a></li>
                <li><a href="#">menu17</a></li>
                <li><a href="#">menu18</a></li>
                <li><a href="#">menu19</a></li>
            </ul>

        </li>   

        </ul> 
    </div>

</nav>