Question

Here is a scraper I created using Python on ScraperWiki:

import lxml.html
import re
import scraperwiki

pattern = re.compile(r'\s')
html = scraperwiki.scrape("http://www.shanghairanking.com/ARWU2012.html")
root = lxml.html.fromstring(html)
for tr in root.cssselect("#UniversityRanking tr:not(:first-child)"):
    if len(tr.cssselect("td.ranking")) > 0 and len(tr.cssselect("td.rankingname")) > 0:
        data = {
            'arwu_rank'  : str(re.sub(pattern, r'', tr.cssselect("td.ranking")[0].text_content())),
            'university' : tr.cssselect("td.rankingname")[0].text_content().strip()
        }
    # DEBUG BEGIN
    if not type(data["arwu_rank"]) is str:
        print type(data["arwu_rank"])
        print data["arwu_rank"]
        print data["university"]
    # DEBUG END
    if "-" in data["arwu_rank"]:
        arwu_rank_bounds  = data["arwu_rank"].split("-")
        data["arwu_rank"] = int( ( float(arwu_rank_bounds[0]) + float(arwu_rank_bounds[1]) ) * 0.5 )
    if not type(data["arwu_rank"]) is int:
        data["arwu_rank"] = int(data["arwu_rank"])
    scraperwiki.sqlite.save(unique_keys=['university'], data=data)

It works perfectly except when scraping the final data row of the table (the "York University" line), at which point instead of lines 9 through 11 of the code causing the string "401-500" to be retrieved from the table and assigned to data["arwu_rank"], those lines somehow seem instead to be causing the int 450 to be assigned to data["arwu_rank"]. You can see that I've added a few lines of "debugging" code to get a better understanding of what's going on, but also that that debugging code doesn't go very deep.

I have two questions:

  1. What are my options for debugging scrapers run on the ScraperWiki infrastructure, e.g. for troubleshooting issues like this? E.g. is there a way to step through?
  2. Can you tell me why the the int 450, instead of the string "401-500", is being assigned to data["arwu_rank"] for the "York University" line?

EDIT 6 May 2013, 20:07h UTC

The following scraper completes without issue, but I'm still unsure why the first one failed on the "York University" line:

import lxml.html
import re
import scraperwiki

pattern = re.compile(r'\s')
html = scraperwiki.scrape("http://www.shanghairanking.com/ARWU2012.html")
root = lxml.html.fromstring(html)
for tr in root.cssselect("#UniversityRanking tr:not(:first-child)"):
    if len(tr.cssselect("td.ranking")) > 0 and len(tr.cssselect("td.rankingname")) > 0:
        data = {
            'arwu_rank'  : str(re.sub(pattern, r'', tr.cssselect("td.ranking")[0].text_content())),
            'university' : tr.cssselect("td.rankingname")[0].text_content().strip()
        }
        # DEBUG BEGIN
        if not type(data["arwu_rank"]) is str:
            print type(data["arwu_rank"])
            print data["arwu_rank"]
            print data["university"]
        # DEBUG END
        if "-" in data["arwu_rank"]:
            arwu_rank_bounds  = data["arwu_rank"].split("-")
            data["arwu_rank"] = int( ( float(arwu_rank_bounds[0]) + float(arwu_rank_bounds[1]) ) * 0.5 )
        if not type(data["arwu_rank"]) is int:
            data["arwu_rank"] = int(data["arwu_rank"])
        scraperwiki.sqlite.save(unique_keys=['university'], data=data)
Was it helpful?

Solution

There's no easy way to debug your scripts on ScraperWiki, unfortunately it just sends your code in its entirety and gets the results back, there's no way to execute the code interactively.

I added a couple more prints to a copy of your code, and it looks like the if check before the bit that assigns data

if len(tr.cssselect("td.ranking")) > 0 and len(tr.cssselect("td.rankingname")) > 0:

doesn't trigger for "York University" so it will be keeping the int value (you set it later on) from the previous time around the loop.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top