使用Scrapy爬虫无法抓取特定网站元素

1 投票
2 回答
769 浏览
提问于 2025-04-18 11:08

我想获取一些工作的网页地址,所以我写了一个爬虫程序。我想用这个路径 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 的时候,它是空的,我就是搞不懂为什么不行,怎么才能修正这个问题,谢谢大家的帮助。

2 个回答

1

这里有一个使用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请求会发生两次。这并不是一个万无一失的解决方案,但对于那些在页面加载完成后才出现的内容,它是有效的。如果你花点时间去了解selenium,你可以在保存页面源代码之前,等待特定事件的触发。

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

更多信息: 从网站抓取数据的最佳方法是什么?

谢谢!

0

Scrapy这个工具不能处理JavaScript。如果你运行下面的命令,你会发现得到的原始HTML中没有你想要的链接。

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

你可以试试PhantomJS或者Selenium这两个工具。

在Chrome浏览器中查看网络请求后,发现这个职位列表是通过一个JSONP请求获取的。你应该能很容易地从中提取到你需要的信息。

撰写回答