如何从scrapy中的json文件中读取行
Posted
技术标签:
【中文标题】如何从scrapy中的json文件中读取行【英文标题】:How to read lines from a json file in scrapy 【发布时间】:2012-12-10 14:53:04 【问题描述】:我有一个 json 文件存储一些用户信息,包括 id
、name
和 url
。 json 文件如下所示:
"link": "https://www.example.com/user1", "id": 1, "name": "user1"
"link": "https://www.example.com/user1", "id": 2, "name": "user2"
这个文件是由一个scrapy spider写的。现在我想从 json 文件中读取 url 并抓取每个用户的网页。但我无法从 json 文件中加载数据。
目前,我不知道如何获取这些 url。我想我应该先从 json 文件中读取这些行。我在 Python shell 中尝试了以下代码:
import json
f = open('links.jl')
line = json.load(f)
我收到以下错误消息:
Raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 2 column 1- line 138 column 497(char498-67908)
我在网上做了一些搜索。搜索表明 json 文件可能存在一些格式问题。但是 json 文件是使用 scrapy 管道创建并填充项目的。有人知道导致错误的原因吗?以及如何解决?关于阅读网址有什么建议吗?
非常感谢。
【问题讨论】:
你确定每个 json 对象之间有一个空行吗?你能确认一下,连同scrapy版本。 【参考方案1】:正如导出器名称所暗示的那样,这些是 json 行。
看看scrapy.contrib.exporter
,看看JsonItemExporter
和JsonLinesItemExporter
之间的区别
这应该可以解决问题:
import json
lines = []
with open('links.jl', 'r') as f:
for line in f:
lines.append(json.loads(line))
【讨论】:
【参考方案2】:AFAIK,一个 JSON 文件应该包含一个对象。在您的情况下,您有几个:
"link": "https://www.domain.com/user1", "id": 1, "name": "user1"
"link": "https://www.domain.com/user1", "id": 2, "name": "user2"
我会这样做:
Python 2.7.3 (default, Sep 26 2012, 21:51:14)
>>> import json
>>> inpt_json = """"link": "https://www.domain.com/user1", "id": 1, "name": "user1"
...
... "link": "https://www.domain.com/user1", "id": 2, "name": "user2""""
>>> for line in inpt_json.splitlines():
... line = line.strip()
... if line:
... print json.loads(line)
...
u'link': u'https://www.domain.com/user1', u'id': 1, u'name': u'user1'
u'link': u'https://www.domain.com/user1', u'id': 2, u'name': u'user2'
>>>
因此,说“我有一个存储一些用户信息的 json 文件……”是不正确的。 Scrapy 将输出存储为“带有 json 编码行的文件”
【讨论】:
【参考方案3】:嗯……这个例外很有趣……我就……把它留在这里(没有保证或良心)。
import json
import re
parse_err = re.compile(
r'Extra data: line \d+ column \d+'
r' - line \d+ column \d+'
r' \(char (\d*).*')
def recover_bad_json(data):
while data:
try:
yield json.loads(data)
return
except ValueError, e:
char = parse_err.match(e.args[0]).group(1)
maybe_data, data = data[:int(char)], data[int(char):]
yield json.loads(maybe_data)
CORPUS = r'''"link": "https://www.domain.com/user1", "id": 1, "name": "user1"
"link": "https://www.domain.com/user1", "id": 2, "name": "user2"
'''
gen_recovered = recover_bad_json(CORPUS)
print gen_recovered.next()
print gen_recovered.next()
print gen_recovered.next()
【讨论】:
【参考方案4】:我之前发现过这种格式设计不佳的 JSON API。这可能不是最好的解决方案,但这是我用来将这种输出转换为包含列表中所有结果对象的 dict 的一个小函数。
def json_parse(data):
d = data.strip().replace("\n\n", ",")
d = '"result":[' + d + ']'
return json.loads(d)
您可能需要稍微修改一下,具体取决于分隔它们的换行符的数量等。使用.read()
读取文件并在数据上调用json_parse
,您应该能够通过访问data["results"]
来迭代所有内容。
如果你可以让你的抓取结果提供有效的 JSON,那就更好了,但与此同时,这样的东西也可以工作。
【讨论】:
【参考方案5】:如果您怀疑 JSON 文档可能格式不正确,我建议您将文档提交至JSONLint。该工具将美化文档格式,并突出在解析过程中遇到的任何结构或样式问题。我过去曾使用此工具在 JSON 文档生成器中查找多余的逗号和断引号。
【讨论】:
erm... 提供的示例显然格式错误:json.loads('')
给出了类似的错误。以上是关于如何从scrapy中的json文件中读取行的主要内容,如果未能解决你的问题,请参考以下文章
Spark - 如何从 S3 读取具有文件名的多个 Json 文件
Python爬虫编程思想(157):使用Scrapy从CSV格式转换到JSON格式
Python爬虫编程思想(157):使用Scrapy从CSV格式转换到JSON格式
Python爬虫编程思想(157):使用Scrapy从CSV格式转换到JSON格式