【问题标题】:Web scraping to download documents with dropdown formWeb 抓取以使用下拉表单下载文档
【发布时间】:2023-02-01 09:03:40
【问题描述】:

我正在尝试抓取世界卫生组织网站 (https://www.who.int/publications/m) >> 使用“世卫组织文件类型“下拉”新闻发布会文字记录”。

过去我能够使用以下脚本将所有指定的文件类型下载到工作目录,但是我无法正确处理下拉列表。

# Working example 

library(tidyverse)
library(rvest)
library(stringr)

page <- read_html("https://www.github.com/rstudio/cheatsheets")

raw_list <- page %>% # takes the page above for which we've read the html
  html_nodes("a") %>%  # find all links in the page
  html_attr("href") %>% # get the url for these links
  str_subset("\\.pdf") %>% # find those that end in pdf only
  str_c("https://www.github.com", .) %>% # prepend the website to the url
  map(read_html) %>% # take previously generated list of urls and read them
  map(html_node, "#raw-url") %>% # parse out the 'raw' url - the link for the download button
  map(html_attr, "href") %>% # return the set of raw urls for the download buttons
  str_c("https://www.github.com", .) %>% # prepend the website again to get a full url
  walk2(., basename(.), download.file, mode = "wb") # use purrr to download the pdf associated with each url to the current working directory

如果我从下面开始。我需要包括哪些步骤来说明“世卫组织文件类型“下拉”新闻发布会文字记录" 和 DL 所有文件到工作目录?

    library(tidyverse)
    library(rvest)
    library(stringr)

    page <- read_html("https://www.who.int/publications/m")

    raw_list <- page %>% # takes the page above for which we've read the html
     html_nodes("a") %>%  # find all links in the page
     html_attr("href") %>% # get the url for these links
     str_subset("\\.pdf") %>% # find those that end in pdf only
     str_c("https://www.who.int", .) %>% # prepend the website to the url
     map(read_html) %>% # take previously generated list of urls and read them
     map(html_node, "#raw-url") %>% # parse out the 'raw' url - the link for the download button
     map(html_attr, "href") %>% # return the set of raw urls for the download buttons
     str_c("https://www.who.int", .) %>% # prepend the website again to get a full url
     walk2(., basename(.), download.file, mode = "wb") # use purrr to download the pdf associated   with each url to the current working directory

目前,我得到以下信息:

Error in .f(.x\[\[1L\]\], .y\[\[1L\]\], ...) : cannot open URL 'NA'
    library(tidyverse)
    library(rvest)
    library(stringr)

    page <- read_html("https://www.who.int/publications/m")

    raw_list <- page %>% # takes the page above for which we've read the html
     html_nodes("a") %>%  # find all links in the page
     html_attr("href") %>% # get the url for these links
     str_subset("\\.pdf") %>% # find those that end in pdf only
     str_c("https://www.who.int", .) %>% # prepend the website to the url
     map(read_html) %>% # take previously generated list of urls and read them
     map(html_node, "#raw-url") %>% # parse out the 'raw' url - the link for the download button
     map(html_attr, "href") %>% # return the set of raw urls for the download buttons
     str_c("https://www.who.int", .) %>% # prepend the website again to get a full url
     walk2(., basename(.), download.file, mode = "wb") # use purrr to download the pdf associated with each url to the current working directory

结果 下载到工作目录的 PDF

【问题讨论】:

    标签: r web-scraping rvest


    【解决方案1】:

    与 rvest 没有太大关系,该文档列表不包含在页面的源代码中(rvest 可以访问)但由浏览器执行的 javascript 拉取(而 rvest 不能这样做)。尽管您可以自己拨打这些电话:

    library(jsonlite)
    library(dplyr)
    library(purrr)
    library(stringr)
    
    # get list of reports, partial API documentation can be found 
    # at https://www.who.int/api/hubs/meetingreports/sfhelp
    # additional parameters (i.e. select & filter) recovered from who.int web requests 
    # skip: number of articles to skip
    get_reports <- function(skip = 0){
      read_json(URLencode(paste0("https://www.who.int/api/hubs/meetingreports?",
                                 "$select=TrimmedTitle,PublicationDateAndTime,DownloadUrl,Tag&",
                                 "$filter=meetingreporttypes/any(x:x eq f6c6ebea-eada-4dcb-bd5e-d107a357a59b)&",
                                 "$orderby=PublicationDateAndTime desc&",
                                 "$count=true&",
                                 "$top=100&",
                                 "$skip=", skip
                                 )), simplifyVector = T) %>% 
        pluck("value") %>% 
        tibble()
    }
    # make 2 requests to collect all current (164) reports ("...&skip=0", "...&skip=100") 
    report_urls <- map_dfr(c(0,100), ~ get_reports(.x))
    report_urls
    #> # A tibble: 164 × 4
    #>    PublicationDateAndTime TrimmedTitle                             Downl…¹ Tag  
    #>    <chr>                  <chr>                                    <chr>   <chr>
    #>  1 2023-01-24T19:00:00Z   Virtual Press conference on global heal… https:… Pres…
    #>  2 2023-01-11T16:00:00Z   Virtual Press conference on global heal… https:… Pres…
    #>  3 2023-01-04T16:00:00Z   Virtual Press conference on global heal… https:… Pres…
    #>  4 2022-12-21T16:00:00Z   Virtual Press conference on global heal… https:… Pres…
    #>  5 2022-12-02T16:00:00Z   Virtual Press conference on global heal… https:… Pres…
    #>  6 2022-11-16T16:00:00Z   COVID-19, Monkeypox & Other Global Heal… https:… Pres…
    #>  7 2022-11-10T22:00:00Z   WHO press conference on global health i… https:… Pres…
    #>  8 2022-10-19T21:00:00Z   WHO press conference on global health i… https:… Pres…
    #>  9 2022-10-19T21:00:00Z   WHO press conference on global health i… https:… Pres…
    #> 10 2022-10-12T21:00:00Z   WHO press conference on COVID-19, monke… https:… Pres…
    #> # … with 154 more rows, and abbreviated variable name ¹​DownloadUrl
    
    # get 1st 3 transcripts, for destfiles plit url by "?", take the 1st part, use basename to extract file name from url
    walk(report_urls$DownloadUrl[1:3], 
         ~ download.file(
           url = .x, 
           destfile = basename(str_split_i(.x, "\?", 1)),mode = "wb"))
    
    # str_split_i() requires stringr >= 1.5.0, feel free to replace with:
    # destfile = basename(str_split(.x, "\?")[[1]][1]),mode = "wb"))
    
    # list downloaded files
    list.files(pattern = "press.*pdf")
    #> [1] "who-virtual-press-conference-on-global-health-issues-11-jan-2023.pdf"
    #> [2] "virtual-press-conference-on-global-health-issues-24-january-2023.pdf"
    #> [3] "virtual-press-conference-on-global-health-issues_4-january-2023.pdf"
    

    创建于 2023-01-28 reprex v2.0.2


    那个“工作示例”来自https://towardsdatascience.com/scraping-downloading-and-storing-pdfs-in-r-367a0a6d9199,除非您已经熟悉那里写的所有内容,否则很难从该文章中获取和应用任何内容。要了解为什么应用为一个站点构建的抓取逻辑几乎对另一个站点不起作用,请查看 https://rvest.tidyverse.org/articles/rvest.htmlhttps://r4ds.hadley.nz/webscraping.html(均来自 rvest 作者)。

    【讨论】:

    • 我似乎遇到了 str_split_i 的问题,错误 Error in str_split_i(.x, "\?, 1) : could not find function "str_split_i", 这阻止了 DL 作为 pdf 进入。我在 Mac 上工作,但不确定是什么原因造成的。有任何想法吗?
    • 这来自 stringr 1.5.0 - tidyverse.org/blog/2022/12/stringr-1-5-0/#splitting,最近有一系列 Tidyverse 更新。您可以将其替换为 destfile = basename(str_split(.x, "\?")[[1]][1]),mode = "wb")) ,并添加了一条注释来回答 cmets。
    猜你喜欢
    • 2023-03-25
    • 2022-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 2021-03-26
    • 1970-01-01
    相关资源
    最近更新 更多