[英]Scraping html text into table with delimiters that do not have a clear pattern using R (rvest)
我只是在學習如何使用 R 從網頁中抓取數據,我遇到了幾個問題。
作為參考,我正在練習的網站在這里: http : //www.rsssf.com/tables/34q.html
據我所知,我從中抓取數據的網站不是表格,因此我無法直接將信息抓取到表格中,因此這是我編寫的代碼,僅包含所有文本:
wcq_1934_html <- read_html("http://www.rsssf.com/tables/34q.html")
wcq_1934_node <- html_nodes(wcq_1934_html, "pre")
wcq_1934_text <- html_text(wcq_1934_node, trim = TRUE)
這會產生一個非常長的文本文件,其中包含我需要的所有信息,只是沒有以理想的方式格式化。
所以我接下來嘗試對這個文本進行子字符串化,以獲得看起來像這樣的輸出。
國家 A - 國家 A 得分 - 國家 B - 國家 B 得分
它不必完全像這樣,我基本上只需要該國家/地區的每場比賽以及他們進了多少球,理想情況下應該與同一場比賽的另一個國家/地區進行比較,這樣我就可以知道誰贏了誰輸了! 我不需要任何其他信息,例如玩游戲的地點等。
所以我嘗試了三種不同的方法來獲得這個:
第一個測試:用破折號分割文本:
test <- strsplit(wcq_1934_text, "-")
df_test <- data.frame(test)
這為我提供了表格中所需的信息,但行與我需要的確切分數不匹配(即立陶宛 0 和瑞典 2 在不同的行中)
第二個測試:按空格分割文本:
test2 <- strsplit(wcq_1934_text, " ")
df_test2 <- data.frame(test2)
這很有用,因為它給了我一行的分數(第一場比賽是 0-2),但是國家在行中的分布不均勻。
第三個測試:按“標簽”拆分文本
test3 <- strsplit(wcq_1934_text, " ")
df_test3 <- data.frame(test3)
這與第一次測試有類似的問題。
任何建議將不勝感激。 這是我有史以來的第一篇 Stack Overflow 帖子,盡管我已經潛伏了一段時間,而且這個網站對我很有幫助。 先感謝您!
這是一個為您提供大部分所需的解決方案,盡管正如 MrFlick 評論的那樣,它對這個頁面來說有點脆弱。 我會繼續使用rvest
,盡管正如 biomiha 所建議的那樣,它在這里並沒有真正給你帶來很多好處(盡管它確實打破了<pre>
塊)。
從您的wcq_1934_text
開始,它是一個長字符串,讓我們用換行符(在本例中為 CRLF)將其分解:
wcq_1934_text <- strsplit(wcq_1934_text, "[\r\n]+")[[1]]
str(wcq_1934_text)
# chr [1:51] "Hosts: Italy (not automatically qualified)" "Holders: Uruguay (did not enter)" "Group 1 [Sweden]" ...
我會使用magrittr
包,因為它有助於使用%>%
非管道分解過程的每個步驟; 你可以轉換它非magrittr
通過改變(例如) func1() %>% func2() %>% func3()
到func3(func2(func1()))
呸)或中間分配的返回值, ret1 <- func1(); ret2 <- func2(ret1); ...
ret1 <- func1(); ret2 <- func2(ret1); ...
ret1 <- func1(); ret2 <- func2(ret1); ...
library(magrittr)
dat <- Filter(function(a) grepl("^[0-9][0-9]", a), wcq_1934_text) %>%
paste(., collapse = "\n") %>%
textConnection() %>%
read.fwf(file = ., widths = c(10, 16, 17, 4, 99), stringsAsFactors = FALSE) %>%
lapply(trimws) %>%
as.data.frame(stringsAsFactors = FALSE)
寬度是脆弱的,並且是該頁面獨有的。 如果其他報告頁面的列布局略有不同,則您需要使用不同的功能,也許是可以自動確定中斷的功能。
head(dat)
# V1 V2 V3 V4 V5
# 1 11.06.33 Stockholm Sweden 6-2 Estonia
# 2 29.06.33 Kaunas Lithuania 0-2 Sweden
# 3 11.03.34 Madrid Spain 9-0 Portugal
# 4 18.03.34 Lisboa Portugal 1-2 Spain
# 5 25.03.34 Milano Italy 4-0 Greece
# 6 25.03.34 Sofia Bulgaria 1-4 Hungary
從這里開始,由您決定要使用哪些列。
例如,處理日期,您可能需要:
dat$V1 <- as.POSIXct(gsub("([0-9]+)$", "19\\1", dat$V1), format = "%d.%m.%Y")
dat$V1
# [1] "1933-06-11 PST" "1933-06-29 PST" "1934-03-11 PST" "1934-03-18 PST" "1934-03-25 PST" "1934-03-25 PST" "1934-04-25 PST" "1934-04-29 PST"
# [9] "1933-10-15 PST" "1934-03-15 PST" "1933-09-24 PST" "1933-10-29 PST" "1934-04-29 PST" "1934-02-25 PST" "1934-04-08 PST" "1934-04-29 PST"
# [17] "1934-03-11 PST" "1934-04-15 PST" "1934-01-28 PST" "1934-02-01 PST" "1934-02-04 PST" "1934-03-04 PST" "1934-03-11 PST" "1934-03-18 PST"
# [25] "1934-05-24 PST" "1934-03-16 PST" "1934-04-06 PST"
gsub
東西是因為as.POSIXct
假設小於 69 的兩位數年份是在 20 世紀,19 是 69-99。
對分數使用strsplit
很容易,但您也可以這樣做:
library(tidyr)
dat %>%
separate(V4, c("score1", "score2"), sep="-") %>%
head()
# Warning: Too few values at 1 locations: 10
# V1 V2 V3 score1 score2 V5
# 1 1933-06-11 Stockholm Sweden 6 2 Estonia
# 2 1933-06-29 Kaunas Lithuania 0 2 Sweden
# 3 1934-03-11 Madrid Spain 9 0 Portugal
# 4 1934-03-18 Lisboa Portugal 1 2 Spain
# 5 1934-03-25 Milano Italy 4 0 Greece
# 6 1934-03-25 Sofia Bulgaria 1 4 Hungary
(警告是意料之中的,因為沒有玩過一場比賽,所以得分為"n/p"
。您可能希望在嘗試拆分之前處理V4
中的V4
分值,也許用NA
替換任何不是 numeric-dash-numeric 的值.)
同樣特定於這個特定站點,但可能更容易概括:
library(rvest)
library(purrr)
library(dplyr)
library(stringi)
pg <- read_html("http://www.rsssf.com/tables/34q.html")
定位<pre>
並去掉一些不屬於“表格”的東西:
html_nodes(pg, "pre") %>%
html_text() %>%
stri_split_lines() %>%
flatten_chr() %>%
discard(stri_detect_regex, "^(NB| )") -> lines
現在,我們得到每個“組”的開始和結束行索引:
starts <- which(grepl("^Group", lines))
ends <- c(starts[-1], length(lines))
我們迭代這些開始和結束,然后:
如果需要,我可以對以下內容進行更多注釋:
map2_df(starts, ends, ~{
grp_info <- stri_match_all_regex(lines[.x], "Group ([[:digit:]]+) \\[(.*)]")[[1]][,2:3]
lines[(.x+1):.y] %>%
discard(stri_detect_regex, "(^[^[:digit:]]| round)") %>%
discard(`==`, "") -> grp
if (length(grp) == 0) return(NULL)
stri_split_regex(grp, "\ \ +") %>%
map_df(~{
.x[1:4] %>%
as.list() %>%
set_names(c("date", "team_a", "team_b", "score_team")) %>%
flatten_df() %>%
separate(score_team, c("score", "team_c"), sep=" ") %>%
mutate(group_num = grp_info[1], group_info = grp_info[2]) %>%
separate(date, c("d", "m", "y")) %>%
mutate(date = as.Date(sprintf("19%s-%s-%s", y, m, d))) %>%
select(-d, -m, -y)
})
})
## # A tibble: 27 x 7
## team_a team_b score team_c group_num group_info date
## <chr> <chr> <chr> <chr> <chr> <chr> <date>
## 1 Stockholm Sweden 6-2 Estonia 1 Sweden 1933-06-11
## 2 Kaunas Lithuania 0-2 Sweden 1 Sweden 1933-06-29
## 3 Madrid Spain 9-0 Portugal 2 Spain 1934-03-11
## 4 Lisboa Portugal 1-2 Spain 2 Spain 1934-03-18
## 5 Milano Italy 4-0 Greece 3 Italy 1934-03-25
## 6 Sofia Bulgaria 1-4 Hungary 4 Hungary, Austria 1934-03-25
## 7 Wien Austria 6-1 Bulgaria 4 Hungary, Austria 1934-04-25
## 8 Budapest Hungary 4-1 Bulgaria 4 Hungary, Austria 1934-04-29
## 9 Warszawa Poland 1-2 Czechoslovakia 5 Czechoslovakia 1933-10-15
## 10 Praha Czechoslovakia n/p Poland 5 Czechoslovakia 1934-03-15
## 11 Beograd Yugoslavia 2-2 Switzerland 6 Romania, Switzerland 1933-09-24
## 12 Bern Switzerland 2-2 Romania 6 Romania, Switzerland 1933-10-29
## 13 Bucuresti Romania 2-1 Yugoslavia 6 Romania, Switzerland 1934-04-29
## 14 Dublin Ireland 4-4 Belgium 7 Netherlands, Belgium 1934-02-25
## 15 Amsterdam Netherlands 5-2 Ireland 7 Netherlands, Belgium 1934-04-08
## 16 Antwerpen Belgium 2-4 Netherlands 7 Netherlands, Belgium 1934-04-29
## 17 Luxembourg Luxembourg 1-9 Germany 8 Germany, France 1934-03-11
## 18 Luxembourg Luxembourg 1-6 France 8 Germany, France 1934-04-15
## 19 Port-au-Prince Haiti 1-3 Cuba 11 USA 1934-01-28
## 20 Port-au-Prince Haiti 1-1 Cuba 11 USA 1934-02-01
## 21 Port-au-Prince Haiti 0-6 Cuba 11 USA 1934-02-04
## 22 Cd. de Mexico Mexico 3-2 Cuba 11 USA 1934-03-04
## 23 Cd. de Mexico Mexico 5-0 Cuba 11 USA 1934-03-11
## 24 Cd. de Mexico Mexico 4-1 Cuba 11 USA 1934-03-18
## 25 Roma USA 4-2 Mexico 11 USA 1934-05-24
## 26 Cairo Egypt 7-1 Palestina 12 Egypt 1934-03-16
## 27 Tel Aviv Palestina 1-4 Egypt 12 Egypt 1934-04-06
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.