在R中使用rvest进行网页抓取

wz1wpwve  于 2023-11-14  发布在  其他
关注(0)|答案(2)|浏览(261)

我想提取的影响力排名表整齐与列排名,大学名称,可持续发展目标1,可持续发展目标2,可持续发展目标3,可持续发展目标4,和总体得分,国家。以下是我尝试的代码。

  1. library(tidyverse)
  2. library(rvest)
  3. link <- "https://www.timeshighereducation.com/impactrankings"
  4. selector <- "#block-system-main > div > div.container"
  5. webpage <- read_html(link)
  6. data <- html_nodes(webpage, selector)
  7. content <- html_text(data)
  8. content

字符串
上面的代码没有达到我的目的。我试图从网页上的大学影响力排名表中提取数据,并将其组织成一个整洁的格式。

brvekthn

brvekthn1#

rvest问题的一般提示适用:在使用rvest之前,尝试temporarily blocking Javascript in your browser并重新加载页面。如果您想要的信息没有出现,则信息很可能是用JavaScript加载的,因此rvest不是该工作的工具。
回退选项包括:

  • 我希望能在Inspector的Network选项卡中看到JSON文件
  • 或者使用Selenium。

在这种情况下,我们是幸运的:
x1c 0d1x的数据
我们想要的文件是以world_impact_rankings开头的文件。我们可以通过以下方式获得URL:
1.在我们的浏览器中打开网页(截图是Chrome的,但与其他浏览器相同)
1.右键点击页面的任何地方,打开“检查”。应该会弹出一些东西,可能在浏览器窗口的底部
1.在这个新的区域(检查器)中,应该有一个网络标签在它的顶部,就像我的截图一样。
1.根据我的经验,你总是需要重新加载页面,让Network选项卡开始列出网络请求,所以重新加载页面。你现在应该看到很多请求被记录下来。
1.通过使用左上角的过滤器搜索框过滤请求,只过滤带有JSON文件的请求
1.找到您要查找的请求,右键单击它>复制>复制链接地址(如果您使用Firefox,它可能会说复制URL,这都是一样的)
现在我们有了URL,我们可以使用JSONlite将其加载到R中:

  1. # (install if necessary, and) load jsonlite
  2. pacman::p_load(jsonlite)
  3. # it's best for you to do this yourself, as 1. the links are likely going to change into the future, and 2. it's best if I don't spoonfeed you everything! :-)
  4. link <- "insert your link here"
  5. # load the data
  6. data <- fromJSON(link)
  7. names(data) # [1] "data" "subjects" "locations" "pillars"

字符串
JSON文件包括四组不同的数据:“subjects”,它看起来像是一个命名的主题列表及其相应的代码,“locations”(每个国家的某种id),“pillars”(可能是内部模型数据)和“data”,它是其他所有内容,以及您正在寻找的数据。

  1. df <- data$data |> dplyr::as_tibble() # I used as_tibble() here because R's default way of displaying a dataframe is to print the entire thing, which is a bit of a mess when it has 1591 rows and 22 columns, as in the example below. R knows not to print every row nor every column of a tibble, but converting it to a tibble() isn't strictly necessary
  2. df


输出量:

  1. # A tibble: 1,591 × 22
  2. rank_order rank name scores_overall scores_overall_rank record_type
  3. <chr> <chr> <chr> <chr> <chr> <chr>
  4. 1 1 1 Western Sydn 99.4 1 master_acc
  5. 2 2 2 University o 97.5 2 master_acc
  6. 3 3 3 Queens Univ 97.2 3 master_acc
  7. 4 4 4 Universiti S 96.9 4 master_acc
  8. 5 5 5 University o 96.6 5 master_acc
  9. 6 6 6 Arizona Stat 96.5 6 public
  10. 7 7 =7 University o 96.4 7 master_acc
  11. 8 8 =7 RMIT Univers 96.4 8 master_acc
  12. 9 9 =9 Aalborg Univ 95.8 9 master_acc
  13. 10 10 =9 University o 95.8 10 master_acc
  14. # ℹ 1,581 more rows
  15. # ℹ 16 more variables: member_level <chr>, url <chr>, nid <int>,
  16. # location <chr>, stats_number_students <chr>,
  17. # stats_student_staff_ratio <chr>, stats_pc_intl_students <chr>,
  18. # stats_female_male_ratio <chr>, aliases <chr>, subjects_offered <chr>,
  19. # best_scores <chr>, closed <lgl>, unaccredited <lgl>, disabled <lgl>,
  20. # apply_link <chr>, cta_button <df[,2]>


上面的排名只是为了整体排名。为了其他的排名,因为只有四个其他的排名,很容易通过重复上面的过程来获得这些排名。如果你在每个SDG上都这样做,那么我建议自动化这个过程(URL是在网站上的一些JSON中找到的,所以你可以抓取URL(例如,像margusl的答案),然后重复上面的过程)。
一个注意:你的问题-你说:

  • “我想提取的影响力排名表整齐的列排名,大学名称,可持续发展目标1,可持续发展目标2,可持续发展目标3,可持续发展目标4,和总体得分,国家。"*.

我想这是为了一项任务吧?如果是的话,你可能想和你的导师谈谈,问他们是否理解整洁的数据实际上意味着什么,因为他们所要求的,像SDG数字这样的信息存储在列的名称中并不是这样。整理这些数据意味着保持数据的长度,并添加一个SDG数字列,上面的数据是“总体”,还有其他东西的号码

展开查看全部
js5cn81o

js5cn81o2#

实际的表数据以JSON的形式提供,而JSON又包含了SGD排名和分数的HTML片段。我们可以首先从页面源中提取JSON的URL,然后解析HTML来提取SGD数据:

  1. library(dplyr, warn.conflicts = FALSE)
  2. library(tidyr)
  3. library(purrr)
  4. library(rvest)
  5. library(stringr)
  6. # extract SGD values from html, returns list of lists for every record:
  7. # List of 4
  8. # $ :List of 2
  9. # ..$ rnk: chr "5"
  10. # ..$ val: chr "80.3"
  11. # $ :List of 2
  12. # ..$ rnk: chr "12"
  13. # ..$ val: chr "93.4"
  14. # $ :List of 2
  15. # ..$ rnk: chr "15"
  16. # ..$ val: chr "96.7"
  17. # $ :List of 2
  18. # ..$ rnk: chr "17"
  19. # ..$ val: chr "98.8"
  20. parse_sgd_row <- function(html){
  21. read_html(html) %>%
  22. html_elements(".sdg-score-multi__item") %>%
  23. map(\(sdg_item) list(rnk = html_element(sdg_item, ".sdg-score-multi__number") %>% html_text2(),
  24. val = html_element(sdg_item, ".sdg-score-multi__value") %>% html_text2()))
  25. }
  26. # extract url of the JSON that hold table content
  27. # ( extract part of embedded js code and parse it as JSON )
  28. json_url <- read_html("https://www.timeshighereducation.com/impactrankings") %>%
  29. html_elements("script") %>%
  30. pluck(10) %>%
  31. html_text() %>%
  32. str_split("\n") %>%
  33. pluck(1) %>%
  34. str_subset(fixed("function init_drupal_core_settings()")) %>%
  35. str_extract("(?<=Drupal.settings, ).*(?=\\)\\;)") %>%
  36. jsonlite::parse_json() %>%
  37. pluck("the_data_rankings", "#datatable-1", "ajax", "url")
  38. json_url
  39. #> [1] "https://www.timeshighereducation.com/sites/default/files/the_data_rankings/world_impact_rankings_2023_0_en_a9364380c7df0f3c145f81db79c61be3.json"
  40. # extract table from JSON
  41. ranking <- jsonlite::fromJSON(json_url)$data %>% as_tibble()
  42. glimpse(ranking)
  43. #> Rows: 1,591
  44. #> Columns: 22
  45. #> $ rank_order <chr> "1", "2", "3", "4", "5", "6", "7", "8", "9",…
  46. #> $ rank <chr> "1", "2", "3", "4", "5", "6", "=7", "=7", "=…
  47. #> $ name <chr> "Western Sydney University", "University of …
  48. #> $ scores_overall <chr> "99.4", "97.5", "97.2", "96.9", "96.6", "96.…
  49. #> $ scores_overall_rank <chr> "1", "2", "3", "4", "5", "6", "7", "8", "9",…
  50. #> $ record_type <chr> "master_account", "master_account", "master_…
  51. #> $ member_level <chr> "0", "6", "11", "0", "0", "11", "0", "0", "1…
  52. #> $ url <chr> "/world-university-rankings/western-sydney-u…
  53. #> $ nid <int> 1014, 512, 639, 131486, 808, 591, 564, 915, …
  54. #> $ location <chr> "Australia", "United Kingdom", "Canada", "Ma…
  55. #> $ stats_number_students <chr> "36,033", "37,035", "26,556", "23,492", "18,…
  56. #> $ stats_student_staff_ratio <chr> "40.3", "14.2", "26.2", "11.6", "22.9", "19.…
  57. #> $ stats_pc_intl_students <chr> "22%", "44%", "17%", "17%", "36%", "17%", "2…
  58. #> $ stats_female_male_ratio <chr> "58 : 42", "55 : 45", "59 : 41", "64 : 36", …
  59. #> $ aliases <chr> "Western Sydney University University of Wes…
  60. #> $ subjects_offered <chr> "Civil Engineering,Geology, Environmental, E…
  61. #> $ best_scores <chr> "<a role=\"button\" class=\"sdg-score-multi_…
  62. #> $ closed <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FA…
  63. #> $ unaccredited <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FA…
  64. #> $ disabled <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FA…
  65. #> $ apply_link <chr> NA, "https://www.timeshighereducation.com/st…
  66. #> $ cta_button <df[,2]> <data.frame[26 x 2]>
  67. # work with a subset of columns,
  68. # switch to rowwise to parse each individual html snippet in
  69. # best_scores column to extacr SGD values;
  70. # quite a slow process, test with first 10 rows
  71. ranking[1:10,] %>%
  72. select(rank_order, rank, name, scores_overall, location, best_scores) %>%
  73. rowwise() %>%
  74. mutate(sgd = parse_sgd_row(best_scores) %>% list(), .keep = "unused") %>%
  75. ungroup() %>%
  76. unnest_wider(sgd, names_sep = ".") %>%
  77. unnest_wider(starts_with("sgd"), names_sep = ".")

字符串
前10行的结果帧:

  1. #> # A tibble: 10 × 13
  2. #> rank_order rank name scores_overall location sgd.1.rnk sgd.1.val sgd.2.rnk
  3. #> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
  4. #> 1 1 1 Weste… 99.4 Austral… 5 80.3 12
  5. #> 2 2 2 Unive… 97.5 United … 15 97.4 12
  6. #> 3 3 3 Queen… 97.2 Canada 2 90.6 16
  7. #> 4 4 4 Unive… 96.9 Malaysia 16 94.1 2
  8. #> 5 5 5 Unive… 96.6 Austral… 13 92.8 15
  9. #> 6 6 6 Arizo… 96.5 United … 15 95.4 14
  10. #> 7 7 =7 Unive… 96.4 Canada 9 99.4 2
  11. #> 8 8 =7 RMIT … 96.4 Austral… 10 92.1 8
  12. #> 9 9 =9 Aalbo… 95.8 Denmark 4 90.6 10
  13. #> 10 10 =9 Unive… 95.8 Canada 11 91.8 13
  14. #> # ℹ 5 more variables: sgd.2.val <chr>, sgd.3.rnk <chr>, sgd.3.val <chr>,
  15. #> # sgd.4.rnk <chr>, sgd.4.val <chr>


创建于2023-11-06附带reprex v2.0.2

展开查看全部

相关问题