r - 使用 rvest 包的网页抓取结果为空
问题描述
在下面的链接中有一个按国家/地区划分的税表,我想将其抓取到包含 Country 和 Tax 列的数据框中。
我尝试使用 rvest 包如下获取我的 Country 列,但我生成的列表是空的,我不明白为什么。
我将不胜感激有关解决此问题的任何指示。
library(rvest)
d1 <- read_html(
"http://taxsummaries.pwc.com/ID/Corporate-income-tax-(CIT)-rates"
)
TaxCountry <- d1 %>%
html_nodes('.countryNameQC') %>%
html_text()
解决方案
当 javascript 在浏览器中运行时,数据会动态加载并更改 DOM。这不会发生在rvest
.
浏览器中的以下选择器将隔离您的节点:
.twoCountryWrapper .countryNameAndYearQC:nth-child(1) .countryNameQC
.twoCountryWrapper .countryNameAndYearQC:nth-child(1) .countryYear
.twoCountryWrapper .countryNameAndYearQC:nth-child(2) .countryNameQC
.twoCountryWrapper .countryNameAndYearQC:nth-child(2) .countryYear
但是,这些课程甚至没有rvest
回报。
感兴趣的数据实际上存储在几个节点中;所有这些都在 . 的公共前缀内具有 ID dspQCLinks
。里面的数据如下:
因此,您可以使用以运算符 (^) 开头的 css attribute = value 语法收集所有这些节点:
html_nodes(page, "[id^=dspQCLinks]")
然后提取文本并组合成一个字符串
paste(html_text(html_nodes(page, "[id^=dspQCLinks]")), collapse = '')
现在表中的每一行都由 分隔!,
,因此我们可以对其进行拆分以生成行:
info = strsplit(paste(html_text(html_nodes(page, "[id^=dspQCLinks]")), collapse = ''),"!,")[[1]]
示例行将如下所示:
"Albania@/uk/taxsummaries/wwts.nsf/ID/Albania-Corporate-Taxes-on-corporate-income@15"
如果我们在 上拆分每一行@
,我们想要的数据位于索引 1 和 3:
arr = strsplit(i, '@')[[1]]
country <- arr[1]
tax <- arr[3]
感谢@Brian 的反馈,我已经删除了我必须构建数据框的循环,并替换为引用@Brian,
str_split_fixed(info, "@", 3)
[which] 为您提供了一个字符矩阵,可以直接强制转换为数据框。
df <- data.frame(str_split_fixed(info, "@", 3))
然后删除 df 底部的空行。
df <- df[df$Country != "",]
df样本:
R
library(rvest)
library(stringr)
library(magrittr)
page <- read_html('http://taxsummaries.pwc.com/ID/Corporate-income-tax-(CIT)-rates')
info = strsplit(paste(html_text(html_nodes(page, "[id^=dspQCLinks]")), collapse = ''),"!,")[[1]]
df <- data.frame(str_split_fixed(info, "@", 3))
colnames(df) <- c("Country","Link","Tax")
df <- subset(df, select = c("Country","Tax"))
df <- df[df$Country != "",]
View(df)
Python:
我首先在 python 中这样做,因为对我来说更快:
import requests
from bs4 import BeautifulSoup as bs
import pandas as pd
r = requests.get('http://taxsummaries.pwc.com/ID/Corporate-income-tax-(CIT)-rates')
soup = bs(r.content, 'lxml')
text = ''
for i in soup.select('[id^=dspQCLinks]'):
text+= i.text
rows = text.split('!,')
countries = []
tax_info = []
for row in rows:
if row:
items = row.split('@')
countries.append(items[0])
tax_info.append(items[2])
df = pd.DataFrame(list(zip(countries,tax_info)))
print(df)
阅读:
推荐阅读
- python - 如何在 Python 中创建带有负 id 的 JSON
- angular - 垫子对话框不作为弹出窗口打开
- git - 如何关闭 IntelliJ 自动 repo 发现 VCS/Git
- laravel - Laravel 按儿童价值排序
- mongodb - 在 MeteorJS 中获取原始 mongo db 引用
- php - Laravel sync() 与多维数组
- arrays - 第 k 个最大元素的 QuickSelect 与 MaxHeap
- php - PHP if in foreach 给出对象
- python - Colaboratory 中 plot_model() 的“断言错误”
- svg - 曲线线性渐变