# Web Scraping Reference: Cheat Sheet for Web Scraping using R Inspired by Hartley Brody, this cheat sheet is about web scraping using [rvest](https://github.com/hadley/rvest),[httr](https://github.com/r-lib/httr) and [Rselenium](https://github.com/ropensci/RSelenium). It covers many topics in this [blog](https://blog.hartleybrody.com/web-scraping-cheat-sheet/). While Hartley uses python's requests and beautifulsoup libraries, this cheat sheet covers the usage of httr and rvest. While rvest is good enough for many scraping tasks, httr is required for more advanced techniques. Usage of Rselenium(web driver) is also covered. I also recommend the book [The Ultimate Guide to Web Scraping](https://blog.hartleybrody.com/guide-to-web-scraping/) by Hartley Brody. Though it uses Python libraries, the underlying logic of web scraping is the same. The same strategies can be applied using any languages including R. Please post issues [here](https://github.com/yusuzech/r-web-scraping-cheat-sheet/issues) if you find any errors or have any recommendations. # Table of Contents 1. Web Scraping using rvest and httr 1. Useful Libraries and Resources 2. Making Simple Requests 3. Inspecting Response 4. Extracting Elements from HTML 5. Storing Data in R 1. Storing Data as list 2. Storing Data as data.frame 6. Saving Data to disk 1. Saving Data to csv 2. Saving Data to SQLite Database 7. More Advanced Topics 1. Javascript Heavy Websites 2. Content Inside iFrames 3. Sessions and Cookies 4. Delays and Backing Off 5. Spoofing the User Agent 6. Using Proxy Servers 7. Setting Timeouts 8. Handling Network Errors 9. Downloading Files 10. Logins and Sessions 11. Web Scraping in Parallel 2. Web Scraping using Rselenium 1. Why RSelenium 1. Pros and Cons from Using RSelenium 2. Useful Resources 2. Interacting with the Web Driver In Rselenium 1. How to Start 2. Navigating to different URLs 3. Simulating Scrolls, Clicks, Text Inputs, Logins, and Other Actions 3. Extract Content from the Web Page 1. Extracting Content using Rselenium 2. Extracting Content using Parsed Page Source and `rvest` 4. miscellanea 1. Javascript 2. Iframe 3. Change Log # 1. Web Scraping using rvest and httr ## 1.1. Useful Libraries and Resources [rvest](https://github.com/hadley/rvest) is built upon the xml2 package and also accept config from the `httr` package. For the most part, we only need `rvest`. However, we need `httr` if we want to add extra configurations. To install those two packages: ```r install.packages("rvest") install.packages("httr") ``` To load them: ```r require(rvest) require(httr) ``` There are many resources available online; these are what I found to be the most useful: 1. [w3schools CSS selectors reference](https://www.w3schools.com/CSSref/css_selectors.asp) : if you forget CSS syntax, just check it here 1. [w3schools XPATH reference](): XPATH is an alternative in selecting elements on websites. It's harder to learn but it's more flexible and robust. 1. [CSS Diner](https://flukeout.github.io/) : the easiest way to learn and understand CSS by playing games. 1. [Chrome CSS selector plugin](https://selectorgadget.com/): a convenient tool to use for choosing CSS selector. 1. [ChroPath](): a very convenient tool for choosing XPATH. 1. [Stack Overflow](https://stackoverflow.com/) : You can find answers to most of your problems, no matter it's web scraping, rvest or CSS. 1. [Web Scraping Sandbox](http://toscrape.com/): Great place to test your web scraping skills. **Functions and classes in rvest/httr:** Sometimes you may get confused about all the functions and classes you have. You can review this image at the moment. ![](resources/functions_and_classes.png) \*\* Please notice that: somtimes response could be JSON or other formats instead of HTML. In those cases you need other functions to parse the content(e.g. jsonlite::fromJSON() to parse a JSON string to a list). ## 1.2. Making Simple Requests rvest provides two ways of making request: `read_html()` and `html_session()` `read_html()` can parse a HTML file or an url into xml document. `html_session()` is built on `GET()` from httr package and can accept configurations defined by httr package. Reading a url: ```R #making GET request andparse website into xml document pagesource <- read_html("http://example.com/page") #using html_session which creates a session and accept httr methods my_session <- html_session("http://example.com/page") #html_session is built upon httr, you can also get response with a session response <- my_session$response ``` Alternatively, GET and POST method are available in the httr package. ```R library(httr) response <- GET("http://example.com/page") #or response <- POST("http://example.com/page", body = list(a=1,b=2)) ``` ## 1.3. Inspecting Response Check status code: ```R status_code(my_session) status_code(response) ``` Get response and content: ```R #response response <- my_session$response #retrieve content as raw content_raw <- content(my_session$response,as = "raw") #retrieve content as text content_text <- content(my_session$response,as = "text") #retrieve content as parsed(parsed automatically) content_parsed <- content(my_session$response,as = "parsed") ``` \*\*note: Content may be parsed incorrectly sometimes. For those situations, you can parse the content to text or raw and use other libraries or functions to parse it correctly. Search for specific string: ```R library(stringr) #regular expression can also be used here if(str_detect(content_text,"blocked")){ print("blocked from website") } ``` check content type: ```R response$headers$`content-type` ``` check html structure: ```R my_structure <- html_structure(content_parsed) ``` ## 1.4. Extracting Elements from HTML Using the regular expression to scrape HTML is not a very good idea, but it does have its usage like scraping all emails from websites, there is a detailed discussion about this topic on [stackoverflow](https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags). **Using rvest:** I will scrape https://scrapethissite.com/ for demonstration, since it has static HTML: For the purpose of extracting elements, using `read_html()` or `html_session()` are both fine. When using `read_html()`, it returns a xml_document. When using `html_session()`, it creates a session and the response is included. ```R my_session <- html_session("https://scrapethissite.com/pages/simple/") ``` Look for nodes: ```R my_nodes <- my_session %>% html_elements(".country") ``` Look for attributes: ```R my_attributes <- my_session %>% html_elements(".country-capital") %>% html_attr("class") ``` Look for texts: ```R my_texts <- my_session %>% html_elements(".country-capital") %>% html_text() ``` ## 1.5. Storing Data in R rvest can return a vector of elements or even table of elements, so it's easy to store it in R. ### 1.5.1. Storing Data as list Usually, rvest can return a vector, so it's very easy to store it. ```R my_texts <- my_session %>% html_elements(".country-capital") %>% html_text() ``` ### 1.5.2. Storing Data as data.frame We can concatenate vectors in a table or using `html_table()` to extract a HTML table directly into a data.frame. ```R my_country <- my_session %>% html_elements(".country-name") %>% html_text() my_capitals <- my_session %>% html_elements(".country-capital") %>% html_text() my_table <- data.frame(country = my_country, capital = my_capitals) ``` ## 1.6. Saving Data to disk ### 1.6.1. Saving Data to csv If the data is already stored as a data.frame: ```R write.csv(my_table,file="my_table.csv") ``` ### 1.6.2. Saving Data to SQLite Database After creating the database "webscrape.db": ```R library(RSQLite) connection <- dbConnect(SQLite(),"webscrape.db") dbWriteTable(conn = connection,name = "country_capital",value = my_table) dbDisconnect(conn = connection) ``` ## 1.7. More Advanced Topics ### 1.7.1. Javascript Heavy Websites For javascript heavy websites, there are three possible solutions: 1. Execute javascript in R 2. Use Developer tools(e.g. [Network in Chrome](https://developers.google.com/web/tools/chrome-devtools/network-performance/)) 3. Using Rselenium or other web drivers There are pros and cons of each method: 1. Executing Javascript in R is the most difficult one since it requires some knowledge of Javascript, but it makes web-scraping javascript heavy websites possible with rvest. 2. Using Developer tools is not difficult. The pro is that you only need to learn some examples and you can then work on it by yourself. The con is that if the website structure gets more completed, it requires more knowledge of HTTP. 3. The Rselenium is absolutely the easiest solution. The pro is it's easy to learn and use. The con is that it can be unstable sometimes and related resources are very limited online. In many situations, you may need to refer to python codes with selenium package. #### 1.Execute javascript I learned how to use Javascript with this [post](https://datascienceplus.com/scraping-javascript-rendered-web-content-using-r/). Since I'm not an expert in Javascript, I recommend you to search for other related resources online. If you don't know Javascipt, then this method is unlikely to be suitable for you. Since Javascript isn't an easy subject, I don't recommend you to learn it if your only purpose is to use it to do web-scraping in R. The following two methods are much easier. #### 2.Use Developer tools I learned this trick from Hartley's blog; the following section is quoted from his [post](https://blog.hartleybrody.com/web-scraping-cheat-sheet/): >Contrary to popular belief, you do not need any special tools to scrape websites that load their content via Javascript. For the information to get from their server and show up on a page in your browser, that information had to have been returned in an HTTP response somewhere. > >It usually means that you won’t be making an HTTP request to the page’s URL that you see at the top of your browser window, but instead you’ll need to find the URL of the AJAX request that’s going on in the background to fetch the data from the server and load it into the page. > >There’s not really an easy code snippet I can show here, but if you open the Chrome or Firefox Developer Tools, you can load the page, go to the “Network” tab and then look through the all of the requests that are being sent in the background to find the one that’s returning the data you’re looking for. Start by filtering the requests to only XHR or JS to make this easier. > >Once you find the AJAX request that returns the data you’re hoping to scrape, then you can make your scraper send requests to this URL, instead of to the parent page’s URL. If you’re lucky, the response will be encoded with JSON which is even easier to parse than HTML. So, as Hartley said, basically, everything displayed on your browser must be sent to you through JSON, HTML or other formats. What you need to do is to capture this file. I answered a couple of questions on Stack Overflow about scraping JavaScript rendered content. You may have the same problems as in the posts. Please check out the answers, and hope you get the ideas of how to use developer tools. https://stackoverflow.com/questions/50596714/how-to-scrap-a-jsp-page-in-r/50598032#50598032 https://stackoverflow.com/questions/50765111/hover-pop-up-text-cannot-be-selected-for-rvest-in-r/50769875#50769875 https://stackoverflow.com/questions/50900987/scraping-dl-dt-dd-html-data/50922733#50922733 https://stackoverflow.com/questions/50693362/unable-to-extract-thorough-data-using-rvest/50730204#50730204 https://stackoverflow.com/questions/50997094/trouble-reaching-a-css-node/50997121#50997121 https://stackoverflow.com/questions/50262108/scraping-javascript-rendered-content-using-r/50263349#50263349 #### 3.Using Rselenium or other web driver Rselenium launches a Chrome/Firefox/IE browser where you can simulate human actions like clicking on links, scrolling up or down. It is a very convenient tool, and it renders JavaScript and Interactive content automatically, so you don't need to worry about the complex HTTP and AJAX stuff. However, there are also some limitations to it: 1. The first limitation is that: it is very slow. Depending on the complexity of the websites, it could take seconds to render a single page while using httr/rvest takes less than one second. It is fine if you only want to scrape several hundred pages. However, if you want scrape thousands or ten thousands of pages, then the speed will become an issue. 2. The second limitation is that: There are little online resources on Rselenium. In many situations, you can't find related posts on Stack Overflow that solve your problem. You may need to refer to Python/Java Selenium posts for answers, and sometimes answers can't be applied in R. More detailed usage is explained in **Web Scraping using Rselenium**. ### 1.7.2. Content Inside iFrames Iframes are other websites embedded in the websites you are viewing as explained on [Wikipedia](https://en.wikipedia.org/wiki/HTML_element#Frames): > Frames allow a visual HTML Browser window to be split into segments, each of which can show a different document. This can lower bandwidth use, as repeating parts of a layout can be used in one frame, while variable content is displayed in another. This may come at a certain usability cost, especially in non-visual user agents,[[51\]](https://en.wikipedia.org/wiki/HTML_element#cite_note-58) due to separate and independent documents (or websites) being displayed adjacent to each other and being allowed to interact with the same parent window. Because of this cost, frames (excluding the `