Scraping tables on multiple pages with predictable URLs
Last updated on 2026-08-25 | Edit this page
Lets us start by installing the libraries that will give us the necessary functionality to do web scraping
R
install.packages("polite")
install.packages("rvest")
install.packages("tidyverse")
install.packages("purrr")
install.packages("htmlTable")
install.packages("htmltools")
install.packages("scales")
Lets us now activate our installed libraries to activate their functionality
R
library(polite)
library(rvest)
library(tidyverse)
library(purrr)
library(htmlTable)
library(htmltools)
library(scales)
Scraping tables on multiple pages
Scraping predictable URLs
But what if the table is spraed across multiple pages? There’s a way to handle that, but it does required a bit more work than the previous example where all tables were on one page. To learning how to scrape webpages where the table is spread across multiple pages, we’ll use this example: http://www.scrapethissite.com/pages/forms/?page_num=1. This link contains 24 pages with team statistics for all teams in the North American professional National Hockey League from year 1990 to year 2011.
To begin we must inspect the URL. Fortunately for us, each page has a base URL, and then it ends with a number that is the the page number. So e.g. the URL for the first page is http://www.scrapethissite.com/pages/forms/?page_num=1. The URL for the second page is http://www.scrapethissite.com/pages/forms/?page_num=2, and so on until page 24. We can isolate the base URL, which is http://www.scrapethissite.com/pages/forms/?page_num=, and then create 24 URLs, each with a number going from 1 to 24
R
paste0("http://scrapethissite.com/pages/forms/?page_num=", 1:24)
OUTPUT
[1] "http://scrapethissite.com/pages/forms/?page_num=1"
[2] "http://scrapethissite.com/pages/forms/?page_num=2"
[3] "http://scrapethissite.com/pages/forms/?page_num=3"
[4] "http://scrapethissite.com/pages/forms/?page_num=4"
[5] "http://scrapethissite.com/pages/forms/?page_num=5"
[6] "http://scrapethissite.com/pages/forms/?page_num=6"
[7] "http://scrapethissite.com/pages/forms/?page_num=7"
[8] "http://scrapethissite.com/pages/forms/?page_num=8"
[9] "http://scrapethissite.com/pages/forms/?page_num=9"
[10] "http://scrapethissite.com/pages/forms/?page_num=10"
[11] "http://scrapethissite.com/pages/forms/?page_num=11"
[12] "http://scrapethissite.com/pages/forms/?page_num=12"
[13] "http://scrapethissite.com/pages/forms/?page_num=13"
[14] "http://scrapethissite.com/pages/forms/?page_num=14"
[15] "http://scrapethissite.com/pages/forms/?page_num=15"
[16] "http://scrapethissite.com/pages/forms/?page_num=16"
[17] "http://scrapethissite.com/pages/forms/?page_num=17"
[18] "http://scrapethissite.com/pages/forms/?page_num=18"
[19] "http://scrapethissite.com/pages/forms/?page_num=19"
[20] "http://scrapethissite.com/pages/forms/?page_num=20"
[21] "http://scrapethissite.com/pages/forms/?page_num=21"
[22] "http://scrapethissite.com/pages/forms/?page_num=22"
[23] "http://scrapethissite.com/pages/forms/?page_num=23"
[24] "http://scrapethissite.com/pages/forms/?page_num=24"
But what if the URLs were predictable, but did not increase one integer after another, starting from 1? we can handle this by creating a list of URLs using some functions in R, which will concatenate each element of URL, until we for each page have the full URL necessary
In this example we will create URLs which will allow us to download
results from political elections in various states in The United States
in 2012 and 2016. In this case, instead of number starting with 1 and
then increasing one integer at a time, we need to specify in the URL
which year the election took place and in which state it took place. To
do this we first write the name of our new object. Now we need to
concatenate a series of text strings. To indicate that we want to start
concatenation we use the crossing function. The first part
of our URL will be the base URL, which is https://www.example.com/. Then we add state to the URL.
Then we draw a list of states, starting in alphabetical oorder with the
first state, Alaska, and going onwards in alphabetical to the 5th state,
which is California. Then we need to tell R that for each state, it
should create 2 URLs. One with the year number 2012, and one with the
year number 2016. So we put them as a vector. Then we need to tell R
that it should unite all these elements into one URL, and that there
should be no space between the elements that constitute the URL. When
then call the URLs with the function pull
R
urls <-
crossing("https://www.example.com/",
"?state=",
state.abb[1:5],
"?year",
c(2012, 2016)) %>%
unite("urls", sep = "") %>%
pull(urls)
Let us return to the data with hockey results. We know that there are 24 pages with tables containing the statistics, and we have a predictable URL, so we can easily create each URLs for each page. But let us imagine that we have a predictable URL, but we don’t know how many pages there. We need to write a script that will automatically find out how many pages there are. This is really useful if there are 100s of pages, and it would take too long to click to the last page in order to find out how many there are Let us start by scraping the website
R
dat <-
bow("http://www.scrapethissite.com/pages/forms/") %>%
scrape()
We know need to go to the webpage in our internet browser and inspect
the HTML We find that there is an HTML element which shows how many
pages there are in total. This element is called “.pagination>li”. We
can specify that the specific HTML element that we want to work with the
function html_elements. Now we need to draw out the actual
content of the selected HTML-element by using the function
html_text2. The content that we draw out is a series of
numbers, but they are in the format of character. We need to convert
them to numbers by using as.numeric we now have a series of
all page numbers, from 1 to 24. However, we are only interested in the
last page number, which in our case has the highest numerical value. We
can therefore isolate this number by using the function
max
R
n_pages <-
dat %>%
html_elements(".pagination>li") %>%
html_text2() %>%
as.numeric() %>%
max(na.rm = TRUE)
WARNING
Warning in dat %>% html_elements(".pagination>li") %>% html_text2() %>% : NAs
introduced by coercion
Now we can create all the URLs by pasting our basic URL with the page numbers, going from 1 until the last page number. Our URLs become a vector with 24 elements, each element being the base URL with a number at the end
R
urls <- paste0("https://scrapethissite.com/pages/forms/?page_num=", 1:n_pages)
Now it is time to scrape data from all the URLs that we have created.
First we write the name of our new object. Then we use the
map function to tell R that it must do the scrape for each
URL in our urls vector. The we use bow for each URL to
ensure that scraping is allowed. Lastly, we scrape the pages with the
scrape function
R
# downloading multiple pages
dat_all <-
map(urls,
~ bow(.x) %>%
scrape())
The map function returns a list, where each element is a
page.
Now we need to tell R that we want each element in the list to be
combined with the other elements, so that our list can be turned into a
dataframe. First we write the name of our new dataframe. Then we tell R
that it should turn the list elements into a dataframe by using the
map_dfr function. We tell R what the name of our list is,
and that we want to draw the table from each element in the list, and
then we draw the table with html_table
R
# formatting downloaded list into a dataframe
dat_tables <-
map_dfr(dat_all,
~ html_elements(.x, "table") %>%
html_table())