R: веб-соскоб yahoo.finance после 2019 изменения - PullRequest
1 голос
/ 10 октября 2019

Я с радостью просматривал веб-страницы yahoo.finance в течение долгого времени, используя код, по большей части заимствованный из других ответов stackoverflow, и он отлично работал, однако в последние несколько недель Yahoo изменила свои таблицы на складные / расширяемые таблицы. Это сломало код, и, несмотря на все мои усилия в течение нескольких дней, я не могу исправить ошибку.

Вот пример кода, который другие использовали годами (который затем анализируется и обрабатывается впо-разному разными людьми).

library(rvest)
library(tidyverse)

# Create a URL string
myURL <- "https://finance.yahoo.com/quote/AAPL/financials?p=AAPL"

# Create a dataframe called df to hold this income statement called df
df <- myURL %>% 
  read_html() %>% 
  html_table(header = TRUE) %>% 
  map_df(bind_cols) %>% 
  as_tibble()

Может кто-нибудь помочь?


РЕДАКТИРОВАТЬ ДЛЯ БОЛЬШЕ ЯРКОСТИ:

Если вы запустите выше, то посмотрите df вы получите

# A tibble: 0 x 0

В качестве примера ожидаемого результата мы можем попробовать другую страницу yahoo, которая не изменилась, такую ​​как:

 # Create a URL string
myURL2 <-  "https://finance.yahoo.com/quote/AAPL/key-statistics?p=AAPL"

df2 <- myURL2 %>% 
  read_html() %>% 
  html_table(header = FALSE) %>% 
  map_df(bind_cols) %>% 
  as_tibble()

Если вы просматриваете df2, вы получаете tibble of59 наблюдений за двумя переменными, являющимися основной таблицей на этой странице, начиная с

Рыночная капитализация (внутридневная) 5 [значение здесь] Стоимость предприятия 3 [значение здесь] И так далее ...

Ответы [ 3 ]

0 голосов
/ 15 октября 2019

Как упомянуто в комментарии выше, здесь есть альтернатива, которая пытается иметь дело с различными опубликованными размерами таблицы. Я работал над этим и получил помощь от друга.

library(rvest)
library(tidyverse)

url <- https://finance.yahoo.com/quote/AAPL/financials?p=AAPL

# Download the data
raw_table <- read_html(url) %>% html_nodes("div.D\\(tbr\\)")

number_of_columns <- raw_table[1] %>% html_nodes("span") %>% length()

if(number_of_columns > 1){
  # Create empty data frame with the required dimentions
  df <- data.frame(matrix(ncol = number_of_columns, nrow = length(raw_table)),
                      stringsAsFactors = F)

  # Fill the table looping through rows
  for (i in 1:length(raw_table)) {
    # Find the row name and set it.
    df[i, 1] <- raw_table[i] %>% html_nodes("div.Ta\\(start\\)") %>% html_text()
    # Now grab the values
    row_values <- raw_table[i] %>% html_nodes("div.Ta\\(end\\)")
    for (j in 1:(number_of_columns - 1)) {
      df[i, j+1] <- row_values[j] %>% html_text()
    }
  }
view(df)
0 голосов
/ 04 ноября 2019

Этот код не подходит для баланса Amazon (AMZN).

Кроме того, было бы здорово, если бы мы могли очистить квартальную финансовую отчетность ....?

Спасибо.

0 голосов
/ 11 октября 2019

Я очень новичок в R, поэтому изо всех сил пытался найти правильный способ сделать это с purrr. Я уверен, что есть хороший простой способ, и, возможно, кто-то поможет мне / вам с этим. На данный момент я вернулся к использованию цикла.

Это может показаться немного похожим на дома, но я хотел избежать большей части того, что я подозреваю, является динамическим на странице (например, многие из classNames) и предоставить что-то, чтоможет иметь немного более длительный срок годности.

Ваш код не работает, частично, потому что нет элемента table, содержащего эти данные. Вместо этого вы можете собрать «строки» желаемой выходной таблицы, используя более стабильно выглядящий атрибут класса fi-row. Затем в каждой строке можно собрать столбцы, сопоставив элементы с атрибутом title или data-test='fin-col' на основе родительского узла строки.

Я использую регулярное выражение для сопоставления по датам (так как они меняются со временем) и объединить их со статическими двумя заголовками, чтобы получить конечные заголовки данных для вывода. Я ограничиваю регулярное выражение одним текстом узла, который, как я знаю, должен содержать совпадения с образцами, которые являются только теми необходимыми датами.


R:

library(rvest)
library(stringr)
library(magrittr)

page <- read_html('https://finance.yahoo.com/quote/AAPL/financials?p=AAPL')
nodes <- page %>%html_nodes(".fi-row")
df = NULL

for(i in nodes){
  r <- list(i %>%html_nodes("[title],[data-test='fin-col']")%>%html_text())
  df <- rbind(df,as.data.frame(matrix(r[[1]], ncol = length(r[[1]]), byrow = TRUE), stringsAsFactors = FALSE))
}

matches <- str_match_all(page%>%html_node('#Col1-3-Financials-Proxy')%>%html_text(),'\\d{1,2}/\\d{1,2}/\\d{4}')  
headers <- c('Breakdown','TTM', matches[[1]][,1]) 
names(df) <- headers
View(df)

Пример:

enter image description here


Py:

import requests, re
import pandas as pd
import BeautifulSoup as bs

r = requests.get('https://finance.yahoo.com/quote/AAPL/financials?p=AAPL')
soup = bs(r.content, 'lxml')
results = []

for row in soup.select('.fi-row'):
    results.append([i.text for i in row.select('[title],[data-test="fin-col"]')])

p = re.compile(r'\d{1,2}/\d{1,2}/\d{4}')
headers = ['Breakdown','TTM']
headers.extend(p.findall(soup.select_one('#Col1-3-Financials-Proxy').text))
df = pd.DataFrame(results, columns = headers)
print(df)
...