import requests
import lxml.html
import datetime
import re
import urlparse
from mrq.context import connections, log
from mrq.job import queue_job
from mrq.task import Task
from mrq.queue import Queue
class Fetch(Task):
def run(self, params):
collection = connections.mongodb_jobs.simple_crawler_urls
response = requests.get(params["url"])
if response.status_code != 200:
log.warning("Got status %s on page %s (Queued from %s)" % (
response.status_code, response.url, params.get("from")
))
return False
# Store redirects
if response.url != params["url"]:
collection.update({"_id": params["url"]}, {"$set": {
"redirected_to": response.url,
"fetched_date": datetime.datetime.now()
}})
document = lxml.html.fromstring(response.content)
document.make_links_absolute(response.url)
queued_count = 0
document_domain = urlparse.urlparse(response.url).netloc
for (element, attribute, link, pos) in document.iterlinks():
link = re.sub("#.*", "", link or "")
if not link:
continue
domain = urlparse.urlparse(link).netloc
# Don't follow external links for this example
if domain != document_domain:
continue
# We don't want to re-queue URLs twice. If we try to insert a duplicate,
# pymongo will throw an error
try:
collection.insert({"_id": link})
except:
continue
queue_job("crawler.Fetch", {
"url": link,
"from": params["url"]
}, queue="crawl")
queued_count += 1
stored_data = {
"_id": response.url,
"queued_urls": queued_count,
"html_length": len(response.content),
"fetched_date": datetime.datetime.now()
}
collection.update(
{"_id": response.url},
stored_data,
upsert=True
)
return True
class Report(Task):
def run(self, params):
collection = connections.mongodb_jobs.simple_crawler_urls
print()
print("Crawl stats")
print("===========")
print("URLs queued: %s" % collection.find().count())
print("URLs successfully crawled: %s" % collection.find({"fetched_date": {"$exists": True}}).count())
print("URLs redirected: %s" % collection.find({"redirected_to": {"$exists": True}}).count())
print("Bytes fetched: %s" % (list(collection.aggregate([
{"$group": {"_id": None, "sum": {"$sum": "$html_length"}}}
])) or [{}])[0].get("sum", 0))
print()
class Reset(Task):
def run(self, params):
collection = connections.mongodb_jobs.simple_crawler_urls
collection.remove({})
Queue("crawl").empty()