首页 > 解决方案 > 使用 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()

标签: rparsingweb-scrapingrvest

解决方案


当 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)

阅读:

  1. str_split_fixed

推荐阅读