<?xml version="1.0" ?><entry xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:planet="http://planet.intertwingly.net/"><id>http://blog.ezyang.com/?p=10235</id><link href="http://blog.ezyang.com/2021/11/interactive-scraping-with-jupyter-and-puppeteer/" rel="alternate" type="text/html"/><link href="http://blog.ezyang.com/2021/11/interactive-scraping-with-jupyter-and-puppeteer/#comments" rel="replies" type="text/html"/><link href="http://blog.ezyang.com/2021/11/interactive-scraping-with-jupyter-and-puppeteer/feed/atom/" rel="replies" type="application/atom+xml"/><title xml:lang="en-US">Interactive scraping with Jupyter and Puppeteer</title><summary xml:lang="en-US">One of the annoying things about scraping websites is bouncing back and forth between the browser where you are using Dev Tools to work out what selectors you should be using to scrape out data, and your actual scraping script, which is usually some batch program that may have to take a few steps before […]</summary><content type="xhtml" xml:lang="en-US"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">



<p>One of the annoying things about scraping websites is bouncing back and forth between the browser where you are using Dev Tools to work out what selectors you should be using to scrape out data, and your actual scraping script, which is usually some batch program that may have to take a few steps before the step you are debugging.  A batch script is fine once your scraper is up and running, but while developing, it's really handy to pause the scraping process at some page and fiddle around with the DOM to see what to do.</p>
<p>This interactive-style development is exactly what Juypter notebooks shine at; when used in conjunction with a browser-based scraping library like Puppeteer, you can have exactly this workflow.  Here's the setup:</p>
<ol class="arabic simple">
<li>Puppeteer is a JavaScript library, so you'll need a JavaScript kernel for Jupyter to run it. As an extra complication, Puppeteer is also async, so you'll need a kernel that supports async execution. Fortunately, <a class="reference external" href="https://www.npmjs.com/package/ijavascript-await">ijavascript-await</a> provides exactly this. Note that on recent versions of node this package does not compile; you can install this PR which makes this work: <a class="reference external" href="https://github.com/n-riesco/ijavascript/pull/257">https://github.com/n-riesco/ijavascript/pull/257</a> Hypothetically, we should be able to use stock ijavascript when node supports top level await, but this currently does not work: <a class="reference external" href="https://github.com/nodejs/node/issues/40898">https://github.com/nodejs/node/issues/40898</a></li>
<li>Inside the directory you will store your snotebooks, you'll need to <tt class="docutils literal">npm install puppeteer</tt> so that it's available for your notebooks.</li>
<li>Launch Puppeteer with <tt class="docutils literal">let puppeteer = <span class="pre">require('puppeteer');</span> let browser = await <span class="pre">puppeteer.launch({headless:</span> <span class="pre">false});</span></tt> and profit!</li>
</ol>
<p>There will be a live browser instance which you can poke at using Dev Tools, and you type commands into the Jupyter notebook and see how they affect the browser state.</p>
<p>I <a class="reference external" href="https://twitter.com/ezyang/status/1462199995923378179">tweeted about this</a> and the commenters had some good suggestions about other things you could try:</p>
<ul class="simple">
<li>You don't have to use Puppeteer; Selenium can also drive the browser, and it has a Python API to boot (so no faffing about with alternate Jupyter kernels necessary). I personally prefer working in JavaScript for crawlers, since the page scripting itself is also in JavaScript, but this is mostly a personal preference thing.</li>
<li>For simple interactions, where all you really want is to just do a few interactions and record them, <a class="reference external" href="https://github.com/checkly/headless-recorder">Headless Recorder</a> provides a nice extension for just directly recording operations in your browser and then getting them out in executable form. I haven't tried it out yet but it seems like it would be very easy to use.</li>
</ul>
</div></div></content><updated planet:format="November 23, 2021 02:28 PM">2021-11-23T14:28:07Z</updated><published planet:format="November 23, 2021 02:28 PM">2021-11-23T14:28:07Z</published><category scheme="http://blog.ezyang.com" term="Web"/><author><name>Edward Z. Yang</name><uri>http://ezyang.com</uri></author><source><id>http://blog.ezyang.com/feed/atom/</id><link href="http://blog.ezyang.com" rel="alternate" type="text/html"/><link href="http://blog.ezyang.com/feed/atom/" rel="self" type="application/atom+xml"/><subtitle xml:lang="en-US">the arc of software bends towards understanding</subtitle><title xml:lang="en-US">ezyang’s blog</title><updated planet:format="August 22, 2025 03:10 PM">2025-08-22T15:10:50Z</updated><planet:format>atom10</planet:format><planet:bozo>false</planet:bozo><planet:css-id>edward-z-yang</planet:css-id><planet:items_per_page>60</planet:items_per_page><planet:encoding>utf-8</planet:encoding><planet:name>Edward Z. Yang</planet:name><planet:days_per_page>0</planet:days_per_page><planet:http_last_modified>Sat, 30 Aug 2025 13:11:59 GMT</planet:http_last_modified><planet:http_status>200</planet:http_status></source></entry>