Scraping recalcitrant web sites with Python & Selenium

13
Scraping recalcitrant web sites with Python & Selenium Roger Barnes SyPy July 2012

Transcript of Scraping recalcitrant web sites with Python & Selenium

Page 1: Scraping recalcitrant web sites with Python & Selenium

Scraping recalcitrant web sites with Python & Selenium

Roger Barnes

SyPy July 2012

Page 2: Scraping recalcitrant web sites with Python & Selenium

Some sites suck

Page 3: Scraping recalcitrant web sites with Python & Selenium

Some sites suck - "for your own good"

For security reasons, each button is an image, dynamically generated by a hash wrapped in a mess of javascript, randomly placed

Page 4: Scraping recalcitrant web sites with Python & Selenium

...but they work in a web browser!

Let's use the web browser to scrape them

Page 5: Scraping recalcitrant web sites with Python & Selenium

Enter Selenium

Selenium automates browsers

That's it

Page 6: Scraping recalcitrant web sites with Python & Selenium

Selenium can...

● navigate (windows, frames, links)● find elements and parse attributes● interact and trigger events (click, type, ...)● capture screenshots● run javascript● let the browser take care of the hard stuff

(cookies, javascript, sessions, profiles, DOM)

Comes with various components and bindings... including python

Page 7: Scraping recalcitrant web sites with Python & Selenium

General Recipe

Ingredients:● firefox (or chrome)● firebug (or chrome dev tools)● Selenium IDE

○ record a session, write less code● python and its batteries● python-selenium● xvfb and pyvirtualdisplay (optional)● other libraries to taste

○ eg image manipulation, database access, DOM parsing, OCR

Page 8: Scraping recalcitrant web sites with Python & Selenium

General Recipe

Method:● Install requirements (apt-get, pip etc)

○ sudo apt-get install xvfb firefox○ pip install selenium pyvirtualdisplay

● Start up Firefox and Selenium IDE● Record a "test" run through site

○ Add in some assertions along the way● Export test as Python script● Hack from there

○ Loops○ Image/data extraction○ Wrangling data into a database

Page 9: Scraping recalcitrant web sites with Python & Selenium
Page 10: Scraping recalcitrant web sites with Python & Selenium

Example from Selenium IDEclass Ingdirect2(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.implicitly_wait( 30) self.base_url = "https://www.ingdirect.com.au" self.verificationErrors = []

def test_ingdirect2(self): driver = self.driver driver.get(self.base_url + "/client/index.aspx") driver.switch_to_frame('body') # Had to add this driver.find_element_by_id( "txtCIF").clear() driver.find_element_by_id( "txtCIF").send_keys("12345678") driver.find_element_by_id( "objKeypad_B1").click() driver.find_element_by_id( "objKeypad_B2").click() driver.find_element_by_id( "objKeypad_B3").click() driver.find_element_by_id( "objKeypad_B4").click() driver.find_element_by_id( "btnLogin").click() self.assertTrue(self.is_element_present(By.ID, "ctl2_lblBalance"))

But what about that dang keypad? ...

Page 11: Scraping recalcitrant web sites with Python & Selenium

PIL saves the day# Get screenshot for extraction of button imagesscreenshot = driver.get_screenshot_as_base64()im = Image.open(StringIO.StringIO(base64.decodestring(screenshot)))

table = driver.find_element_by_xpath( '//*[@id="objKeypad_divShowAll"]/table')all_buttons = table.find_elements_by_tag_name( "input")

# Determine md5sum of each button by cropping based on element positionsfor button in all_buttons: button_image = im.crop(getcropbox(button)) hexid = hashlib.md5(button_image.tostring()).hexdigest() button_mapping[hexid] = button.get_attribute( "id")

# Now we know which button is which ( based on previous lookup), enter the PINfor char in self.pin: driver.find_element_by_id(button_mapping[hex_mapping[char]]).click()

driver.find_element_by_id( "btnLogin").click()

# We're in!!!11one

Page 12: Scraping recalcitrant web sites with Python & Selenium

But why do all this?

It's my data! ... and I'll graph if i want to

* Actual results may vary. Graph indicates open inodes, not high-roller gambling problem

Page 13: Scraping recalcitrant web sites with Python & Selenium

That's all folks

Slides● http://bit.ly/scrapium

Code● https://gist.github.com/3015852

Me● https://twitter.com/mindsocket● https://github.com/mindsocket● [email protected]