【问题标题】:Failed to crawl element of specific website with scrapy spider无法使用scrapy spider抓取特定网站的元素
【发布时间】:2014-08-16 21:09:56
【问题描述】:

我想获取一些工作的网站地址,所以我写了一个scrapy蜘蛛,我想用xpath://article/dl/dd/h2/a[@class="job-title"]/@href,获取所有值但是当我用命令执行蜘蛛时:

scrapy spider auseek -a addsthreshold=3

用于保存值的变量“urls”是空的,谁能帮我弄清楚,

这是我的代码:

from scrapy.contrib.spiders import CrawlSpider,Rule
from scrapy.selector import Selector
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.conf import settings
from scrapy.mail import MailSender
from scrapy.xlib.pydispatch import dispatcher
from scrapy.exceptions import CloseSpider
from scrapy import log
from scrapy import signals

from myProj.items import ADItem
import time

class AuSeekSpider(CrawlSpider):
    name = "auseek"
    result_address = []
    addressCount = int(0)
    addressThresh = int(0)
    allowed_domains = ["seek.com.au"]
    start_urls = [
        "http://www.seek.com.au/jobs/in-australia/"
    ]

    def __init__(self,**kwargs):
        super(AuSeekSpider, self).__init__()
        self.addressThresh = int(kwargs.get('addsthreshold'))
        print 'init finished...'

    def parse_start_url(self,response):
        print 'This is start url function'
        log.msg("Pipeline.spider_opened called", level=log.INFO)
        hxs = Selector(response)
        urls = hxs.xpath('//article/dl/dd/h2/a[@class="job-title"]/@href').extract()
        print 'urls is:',urls
        print 'test element:',urls[0].encode("ascii")
        for url in urls:
            postfix = url.getAttribute('href')
            print 'postfix:',postfix
            url = urlparse.urljoin(response.url,postfix)
            yield Request(url, callback = self.parse_ad)

        return 


    def parse_ad(self, response):
        print 'this is parse_ad function'
        hxs = Selector(response) 

        item = ADItem()
        log.msg("Pipeline.parse_ad called", level=log.INFO)
        item['name'] = str(self.name)
        item['picNum'] = str(6)
        item['link'] = response.url
        item['date'] = time.strftime('%Y%m%d',time.localtime(time.time()))

        self.addressCount = self.addressCount + 1
        if self.addressCount > self.addressThresh:
            raise CloseSpider('Get enough website address')
        return item

问题是:

urls = hxs.xpath('//article/dl/dd/h2/a[@class="job-title"]/@href').extract()

当我尝试打印出来时,urls 是空的,我只是想不通为什么它不起作用以及如何纠正它,谢谢你的帮助。

【问题讨论】:

    标签: python scrapy element web-crawler


    【解决方案1】:

    Scrapy 不评估 Javascript。如果您运行以下命令,您将看到原始 HTML 不包含您要查找的锚点。

    curl http://www.seek.com.au/jobs/in-australia/ | grep job-title
    

    您应该尝试使用 PhantomJS 或 Selenium。

    在 Chrome 中检查网络请求后,职位列表似乎来自 this JSONP request。应该很容易从中检索到您需要的任何内容。

    【讨论】:

    • 是的,这个 jsonp 请求包含我需要的 ID,但是如何在我的蜘蛛代码中获取请求的地址?
    • @eric,你不能把原来的网址换成新的吗?
    • muh..是的,我可以复制地址,但是我发现每次刷新页面时请求地址都会改变,所以它可能只是一个临时地址并且会在某个时候过期,但我需要每天爬网站,所以需要一个永久地址或者具体的方法来查找json文件的地址。期待您的帮助:)
    • @eric,在jsonp请求参数中,callback可以是任意随机值,usersessionid也可以是任意随机值,_是请求时间戳,其他都可以改成适合您的查询。
    【解决方案2】:

    这是一个在下载处理程序中间件中使用 selenium 和 phantomjs 无头网络驱动程序的工作示例。

    class JsDownload(object):
    
    @check_spider_middleware
    def process_request(self, request, spider):
        driver = webdriver.PhantomJS(executable_path='D:\phantomjs.exe')
        driver.get(request.url)
        return HtmlResponse(request.url, encoding='utf-8', body=driver.page_source.encode('utf-8'))
    

    我希望能够告诉不同的蜘蛛使用哪个中间件,所以我实现了这个包装器:

    def check_spider_middleware(method):
    @functools.wraps(method)
    def wrapper(self, request, spider):
        msg = '%%s %s middleware step' % (self.__class__.__name__,)
        if self.__class__ in spider.middleware:
            spider.log(msg % 'executing', level=log.DEBUG)
            return method(self, request, spider)
        else:
            spider.log(msg % 'skipping', level=log.DEBUG)
            return None
    
    return wrapper
    

    settings.py:

    DOWNLOADER_MIDDLEWARES = {'MyProj.middleware.MiddleWareModule.MiddleWareClass': 500}
    

    为了使包装器工作,所有蜘蛛必须至少具有:

    middleware = set([])
    

    包含一个中间件:

    middleware = set([MyProj.middleware.ModuleName.ClassName])
    

    您可以在请求回调中(在蜘蛛中)实现这一点,但随后 http 请求将发生两次。这不是一个完整的证明解决方案,但它适用于在 .ready() 上加载的内容。如果您花一些时间阅读 selenium,您可以等待特定事件触发,然后再保存页面源代码。

    另一个例子:https://github.com/scrapinghub/scrapyjs

    更多信息:What's the best way of scraping data from a website?

    干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      • 2021-03-04
      • 2013-05-09
      • 2020-10-12
      • 2018-12-20
      相关资源
      最近更新 更多