r - 抓取不同网站中元素数量变化的自由文本
问题描述
我正在抓取以这种格式提供的公司数据库,其中每家公司都位于不同的网站下,由 url 末尾的数字定义(上面的示例是 15310;参见 url)。我正在使用rvest
.
我想提取“Organización”下显示的所有条目。每个变量名称以粗体显示,后跟普通文本中的值。在上面的示例中,有 16 个变量要提取。
这些网站存在两个问题:
- 普通文本不在元素内(而变量名在)。实际上,代码是这样的(注意“值”在外面
label
):
<div class="form-group">
<label for="variable_code">variable_name</label>
Value
</div>
- 并非所有公司都有相同数量的变量(上例中为 16 个)。有些人多,有些人少。尽管如此,
variable_code
并且variable_name
在整个数据库中都是相同的。
我可以想到两种方法来抓取数据。一是固定位置刮。为此,我可以使用“nth-child”类型的 CSS 选择器来获取每个变量。但是,由于公司之间变量的数量会发生变化,我需要将变量名称和值都保存为 R 变量。这显示在下面的代码中(对于一个网站;更多只需要添加循环,这里无关):
library(xml2)
library(rvest)
library(stringr)
url <- "https://tramites.economia.gob.cl/Organizacion/Details/15310"
webpage <- read_html(url) #read webpage
title_html <- html_nodes(webpage, "body > div > div:nth-child(5) > div > div:nth-child(1) > div:nth-child(3)") # this selects by element in division, after which I extract both the variable name and value as elements. Ideally, you want only the value, to allocate to a variable in a dataframe.
title <- html_text(title_html)
variable_name <- trimws(strsplit(title, "\r\n")[[1]][2])
value <- trimws(strsplit(title, "\r\n")[[1]][3])
所以,上面的工作,但它很耗时,因为它将变量名保存为变量,之后我需要转换数据。
另一种选择是根据标签进行刮擦。也就是说,搜索代码中的每个变量并获取其值。就像是:
title_html <- html_nodes(webpage, "body > div > div:nth-child(5) > div > div:nth-child(1) label[for=RazonSocial]")
这种方法的问题是每个变量的值都是自由文本(即在特定元素之外)。因此,它不能通过 CSS 选择器获得,正如许多地方所解释的那样(例如here、here或here)。显然,我无法更改 html 代码。
我可以做些什么来改进抓取过程?我是否坚持使用蛮力,第一种方法,将所有内容提取为变量?或者我能以某种方式提高效率吗?
PS:我想到的一种方法是使用第二种方法以某种方式获取标签所在的位置,然后使用第一种方法获取值。但我怀疑 R 有这个选项(比如address
或cell
在 excel 中)。
解决方案
我会做这样的事情:
library(xml2)
library(rvest)
library(tidyverse)
url <- "https://tramites.economia.gob.cl/Organizacion/Details/15310"
webpage <- read_html(url)
# select every 'cell'
form_groups <- webpage %>%
html_nodes("div.form-group")
# select cell names (label or strong)
form_groups_labels <- form_groups %>%
html_node("label, strong") %>%
html_text()
# select cell contents (text following <br>, or inside p)
form_groups_values <- form_groups %>%
html_node(xpath = "br/following-sibling::text()|p") %>%
html_text(trim = T)
# store it in a table
df <- tibble(
id = 15310,
labels = form_groups_labels,
values = form_groups_values
)
# make it wider if required (after you've gathered all organizations)
df %>%
pivot_wider(id_cols = id,
names_from = labels,
values_from = values)
推荐阅读
- php - 仪表板索引页四个错误,但本地主机工作良好
- python - 如何从 python 脚本打开 .cmd 文件
- mysql - SQL - 多个表 - 始终返回数据或 null
- python - 具有多个元信息的时间序列预测 (GRU)
- android - 改进来自 Tensorflow 的对象检测演示中的相机预览
- python - 如何在 queue.get() 中确定队列项来自哪个线程——python
- regex - Logstash 过滤器,如果字段匹配正则表达式不起作用
- javascript - 使用属性更新对象属性中的数组
- mysql - MYSQL - MATCH AGAINST 得分值 = 0 但在 WHERE 子句中 > 0
- javascript - jQuery计数器并添加一个类但不是前两个?