【问题标题】:Scrape values from HTML select/option tags in R从 R 中的 HTML 选择/选项标签中抓取值
【发布时间】:2014-09-22 02:04:14
【问题描述】:

我正在尝试(相当不成功)使用 R 从网站 (www.majidata.co.ke) 抓取一些数据。我已经设法抓取 HTML 并解析它,但现在有点不确定如何提取我真正需要的东西!

使用XML 库,我使用以下代码抓取我的数据:

majidata_get <- GET("http://www.majidata.go.ke/town.php?MID=MTE=&SMID=MTM=")
majidata_html <- htmlTreeParse(content(majidata_get, as="text"))

这给我留下了(大)XMLDocumentContent。网页上有一个下拉列表,我想从中刮取值(与不同城镇的名称和身份证号有关)。我要提取的位是&lt;option value ="XXX"&gt; 及其后面的大写字母名称之间的数字。

<div class="regiondata">
       <div id="town_data">
        <select id="town" name="town" onchange="town_data(this.value);">
         <option value="0" selected="selected">[SELECT TOWN]</option>
         <option value="611">AHERO</option>
         <option value="635">AKALA</option>
         <option value="625">AWASI</option>
         <option value="628">AWENDO</option>
         <option value="749">BAHATI</option>
         <option value="327">BANGALE</option>

理想情况下,我希望将这些放在 data.frame 中,其中第一列是数字,第二列是名称,例如

ID       Name
611      AHERO
635      AKALA
625      AWASI

等等

我不确定从这里去哪里。我曾想过使用正则表达式并匹配文本中的模式,尽管我从许多论坛中读到这是一个坏主意,使用 xpath 更好/更有效。除了认为我需要使用xpathApplysomehow之外,我不确定从哪里开始。

【问题讨论】:

标签: html r web-scraping rvest


【解决方案1】:

全新的rvest 包可以快速解决此问题,并让您也可以使用合理的 CSS 选择器。

已更新包含第二个请求(参见下面的 cmets)

library(rvest)
library(dplyr)

# gets data from the second popup
# returns a data frame of town_id, town_name, area_id, area_name
addArea <- function(town_id, town_name) {

  # make the AJAX URL and grab the data
  url <- sprintf("http://www.majidata.go.ke/ajax-list-area.php?reg=towns&type=projects&id=%s",
                 town_id)
  subunits <- html(url)

  # reformat into a data frame with the town data
  data.frame(town_id=town_id,
             town_name=town_name,
             area_id=subunits %>% html_nodes("option") %>% html_attr("value"),
             area_name=subunits %>% html_nodes("option") %>% html_text(),
             stringsAsFactors=FALSE)[-1,]

}

# get data from the first popup and put it into a dat a frame
majidata <- html("http://www.majidata.go.ke/town.php?MID=MTE=&SMID=MTM=")
maji <- data.frame(town_id=majidata %>% html_nodes("#town option") %>% html_attr("value"),
                   town_name=majidata %>% html_nodes("#town option") %>% html_text(),
                   stringsAsFactors=FALSE)[-1,]

# pass in the name and id to our addArea function and make the result into
# a data frame with all the data (town and area)
combined <- do.call("rbind.data.frame",
                    mapply(addArea, maji$town_id,  maji$town_name,
                           SIMPLIFY=FALSE, USE.NAMES=FALSE))

# row names aren't super-important, but let's keep them tidy
rownames(combined) <- NULL

str(combined)

## 'data.frame':    1964 obs. of  4 variables:
##  $ town_id  : chr  "611" "635" "625" "628" ...
##  $ town_name: chr  "AHERO" "AKALA" "AWASI" "AWENDO" ...
##  $ area_id  : chr  "60603030101" "60107050201" "60603020101" "61103040101" ...
##  $ area_name: chr  "AHERO" "AKALA" "AWASI" "ANINDO" ...


head(combined)

##   town_id town_name     area_id area_name
## 1     611     AHERO 60603030101     AHERO
## 2     635     AKALA 60107050201     AKALA
## 3     625     AWASI 60603020101     AWASI
## 4     628    AWENDO 61103040101    ANINDO
## 5     628    AWENDO 61103050401      SARE
## 6     749    BAHATI 73101010101    BAHATI

【讨论】:

  • 感谢两者,两种方式都可以完美运行。不过,我还有第二个问题。选择“城镇”后,第一个旁边会出现另一个下拉列表,为您提供每个城镇内的子单元列表。是否可以使用相同的方法从第二个列表中抓取数据?例如如果我对“内罗毕”感兴趣,是否可以使用上述任何一种方法来抓取“内罗毕”内的所有子单元,并反映在第二个下拉框中:“选择区域”?
  • 我正在学习 SO 的工具,但 marty_c 您可能需要使用两个回答者的@tag 开始您的评论,以便他们看到您的评论。其次,他们提供的方法会起作用,但第二个下拉菜单的 URL 会发生变化。
  • 正如@lawyeR 熟练地指出的那样,它只是在抓取另一个网址。从技术上讲,您应该提出一个新问题 :-) 您需要熟悉浏览器的“开发人员”菜单/工具,因为找到这个菜单/工具只是看看调用什么来制作该弹出窗口。注意:这需要几秒钟才能运行,因为它会进行许多 AJAX 调用。添加进度条(推荐)作为练习留给读者。
  • 另外,我强烈建议将生成的数据框保存到 rda 文件(或 CSV 或其他文件)中。重复运行此抓取代码是让您的 IP 地址被禁止访问网站的好方法。 “城镇”和“地区”不太可能经常改变(如果有的话)。
  • @hrbmstr:我很高兴能获得 10 多个代表点数,但我不知道他们为什么会授予我。我没有回答,只是一个谦虚的评论。如果有人赞成我的评论,我不会从小旗子上看到吗?
【解决方案2】:

在 HTML 中使用 xpath 表达式几乎总是比正则表达式更好的选择。鉴于这些数据,您可以提取您所追求的内容

options<-getNodeSet(xmlRoot(majidata_html), "//select[@id='town']/option")

ids <- sapply(options, xmlGetAttr, "value")
names <- sapply(options, xmlValue)

data.frame(ID=ids, Name=names)

返回

   ID          Name
1   0 [SELECT TOWN]
2 611         AHERO
3 635         AKALA
4 625         AWASI
5 628        AWENDO
6 749        BAHATI
...

【讨论】:

    猜你喜欢
    • 2017-05-04
    • 2016-07-28
    • 2013-12-28
    • 2022-07-16
    • 2022-06-11
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多