我试图爬取一些新闻文章的网站。我的start_url包括:
(1) 每篇文章的链接:http://example.com/symbol/TSLA
和
(2) 一个“更多”按钮,它会发出AJAX调用,动态加载相同start_url中的更多文章:http://example.com/account/ajax_headlines_content?type=in_focus_articles&page=0&slugs=tsla&is_symbol_page=true
AJAX调用的一个参数是“page”,每次单击“More”按钮时都会递增。例如,单击“More”一次将加载额外的n篇文章,并在“More”按钮的onClick事件中更新页面参数,以便下次单击“More”时将加载第二页文章(假设最初加载了第0页,第一次单击加载了第1页)。
对于每个“page”,我想使用Rules来抓取每篇文章的内容,但我不知道有多少个“page”,也不想选择任意的m(例如10k)。我似乎无法弄清楚如何设置这个东西。
从这个问题Scrapy Crawl URLs in Order,我尝试创建一个潜在URL列表,但我无法确定如何以及在哪里从池中发送新的URL,在解析前一个URL并确保它包含CrawlSpider的新闻链接后。我的Rules将响应发送到parse_items回调函数,其中解析文章内容。
是否有一种方法可以在应用规则和调用parse_items之前观察链接页面的内容(类似于BaseSpider示例),以便我可以知道何时停止爬取?
简化代码(我删除了几个字段以使其更清晰):
class ExampleSite(CrawlSpider):
name = "so"
download_delay = 2
more_pages = True
current_page = 0
allowed_domains = ['example.com']
start_urls = ['http://example.com/account/ajax_headlines_content?type=in_focus_articles&page=0'+
'&slugs=tsla&is_symbol_page=true']
##could also use
##start_urls = ['http://example.com/symbol/tsla']
ajax_urls = []
for i in range(1,1000):
ajax_urls.append('http://example.com/account/ajax_headlines_content?type=in_focus_articles&page='+str(i)+
'&slugs=tsla&is_symbol_page=true')
rules = (
Rule(SgmlLinkExtractor(allow=('/symbol/tsla', ))),
Rule(SgmlLinkExtractor(allow=('/news-article.*tesla.*', '/article.*tesla.*', )), callback='parse_item')
)
##need something like this??
##override parse?
## if response.body == 'no results':
## self.more_pages = False
## ##stop crawler??
## else:
## self.current_page = self.current_page + 1
## yield Request(self.ajax_urls[self.current_page], callback=self.parse_start_url)
def parse_item(self, response):
self.log("Scraping: %s" % response.url, level=log.INFO)
hxs = Selector(response)
item = NewsItem()
item['url'] = response.url
item['source'] = 'example'
item['title'] = hxs.xpath('//title/text()')
item['date'] = hxs.xpath('//div[@class="article_info_pos"]/span/text()')
yield item