在 Scrapy 中解析 JSON 响应非常常见,特别是当目标网站的 API 返回 JSON 数据时。Scrapy 提供了一些工具和方法来轻松处理 JSON 响应。
1、问题背景
Scrapy中如何解析JSON响应?
有一只爬虫(点击查看源代码),它可以完美地完成常规的HTML页面抓取任务。
但是,想增加一项新功能。想解析一个JSON页面。
以下是想做的事情(这里是用手工完成的,不使用Scrapy):
import requests, json
import datetime
def main():
user_agent = {
'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36'
}
# 这是一个输出JSON的URL:
externalj = 'http://www.thestudentroom.co.uk/externaljson.php?&s='
# 从URL的末尾,它基于时间(unixtime):
past = datetime.datetime.now() - datetime.timedelta(minutes=15)
time = past.strftime('%s')
# 这是完整的URL:
url = externalj + time
# 发出HTTP GET请求:
tsr_data = requests.get(url, headers= user_agent).json()
# 迭代JSON数据并形成URL
# (JSON数据中根本没有URL,必须手动形成):
# URL只需通过将规范链接与线程ID连接就能形成:
for post in tsr_data['discussions-recent']:
link= 'www.thestudentroom.co.uk/showthread.php?t='
return link + post['threadid']
此函数将返回到想抓取的HTML页面(论坛帖子链接)的正确链接。似乎需要创建一个自己的请求对象发送给爬虫中的parse_link?
问题是,该把这段代码放在哪里?对于如何将它合并到Scrapy中感到非常困惑?是否需要创建一个新的爬虫?
最好能与已经有的爬虫一起工作,但不确定是否可行。
对于如何在Scrapy中实现这个功能感到非常困惑。希望有人能提供建议!
当前的爬虫是这样的:
import scrapy
from tutorial.items import TsrItem
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors import LinkExtractor
class TsrSpider(CrawlSpider):
name = 'tsr'
allowed_domains = ['thestudentroom.co.uk']
start_urls = ['http://www.thestudentroom.co.uk/forumdisplay.php?f=89']
download_delay = 2
user_agent = 'youruseragenthere'
thread_xpaths = (
"//tr[@class='thread unread ']@",
"//*[@id='discussions-recent']/li/a",
"//*[@id='discussions-popular']/li/a")
rules = [
Rule(LinkExtractor(allow=('showthread\.php\?t=\d+',),
restrict_xpaths=thread_xpaths),
callback='parse_link', follow=True),]
def parse_link(self, response):
for sel in response.xpath("//li[@class='post threadpost old ']"):
item = TsrItem()
item['id'] = sel.xpath(
"div[@class='post-header']//li[@class='post-number museo']/a/span/text()").extract()
item['rating'] = sel.xpath(
"div[@class='post-footer']//span[@class='score']/text()").extract()
item['post'] = sel.xpath(
"div[@class='post-content']/blockquote[@class='postcontent restore']/text()").extract()
item['link'] = response.url
item['topic'] = response.xpath(
"//div[@class='forum-header section-header']/h1/span/text()").extract()
yield item
2、解决方案
# 添加以下内容到爬虫中:
# 需要一个请求对象。
from scrapy.http import Request
以及:
def parse_start_url(self, response):
if 'externaljson.php' in str(response.url):
return self.make_json_links(response)
parse_start_url似乎做了它所说的事情。它解析了初始URL(起始URL)。只有JSON页面应该在这里处理。
因此需要添加带有HTML URL的特殊JSON URL:
start_urls = ['http://tsr.com/externaljson.php', 'http://tsr.com/thread.html']
现在需要从JSON页面的响应中生成URL,以请求的形式:
def make_json_links(self, response):
''' 从JSON页面创建请求。 '''
数据 = json.loads(response.body_as_unicode())
for post in data['discussions-recent']:
link = 'http://www.tsr.co.uk/showthread.php?t='
full_link = link + str(post['threadid'])
json_request = Request(url=full_link)
return json_request
现在它似乎起作用了。但是,相信这是一个解决此问题的黑客手段且不优雅。以某种方式感觉不对。
它似乎有效,并且它遵循由JSON页面制作的所有链接。也不确定是否应该在里面的某个地方使用yield而不是return…
Scrapy 支持高效处理 JSON 响应,结合 Python 的 json
库可以轻松提取数据。在复杂场景下,可以通过递归、分页处理、调试工具以及自定义请求头,灵活应对各种 JSON 数据结构。