【问题标题】:Extract JSON from Text in python从python中的文本中提取JSON
【发布时间】:2018-12-09 23:39:21
【问题描述】:

我想从日志文本中提取 JSON/字典。

示例日志文本:

2018-06-21 19:42:58 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'locations', 'CLOSESPIDER_TIMEOUT': '14400', 'FEED_FORMAT': 'geojson', 'LOG_FILE': '/geojson_dumps/21_Jun_2018_07_42_54/logs/coastalfarm.log', 'LOG_LEVEL': 'INFO', 'NEWSPIDER_MODULE': 'locations.spiders', 'SPIDER_MODULES': ['locations.spiders'], 'TELNETCONSOLE_ENABLED': '0', 'USER_AGENT': 'Mozilla/5.0'}

2018-06-21 19:43:00 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 369,
 'downloader/request_count': 1,
 'downloader/request_method_count/GET': 1,
 'downloader/response_bytes': 1718,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2018, 6, 21, 14, 13, 0, 841666),
 'item_scraped_count': 4,
 'log_count/INFO': 8,
 'memusage/max': 56856576,
 'memusage/startup': 56856576,
 'response_received_count': 1,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2018, 6, 21, 14, 12, 58, 499385)}

2018-06-21 19:43:00 [scrapy.core.engine] INFO: Spider closed (finished)

我尝试将(\{.+$\}) 作为正则表达式,但它给了我单行上的字典,{'BOT_NAME': 'locations',..., 'USER_AGENT': 'Mozilla/5.0'},这不是预期的。

我要提取的 json/字典: 注意:字典不会有相同的键,可能会有所不同。

{'downloader/request_bytes': 369,
 'downloader/request_count': 1,
 'downloader/request_method_count/GET': 1,
 'downloader/response_bytes': 1718,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2018, 6, 21, 14, 13, 0, 841666),
 'item_scraped_count': 4,
 'log_count/INFO': 8,
 'memusage/max': 56856576,
 'memusage/startup': 56856576,
 'response_received_count': 1,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2018, 6, 21, 14, 12, 58, 499385)}

【问题讨论】:

标签: python regex python-3.x


【解决方案1】:

编辑:JSON 跨越多行,所以这就是它的作用:

import re

re_str = '\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \[scrapy\.statscollectors] INFO: Dumping Scrapy stats:.({.+?\})'
stats_re = re.compile(re_str, re.MULTILINE | re.DOTALL)

for match in stats_re.findall(log):
    print(match)

如果您只关注来自 statscollector 的行,那么这应该可以让您到达那里(假设它也都在一行上):

^.*?\[scrapy.statscollectors] INFO: Dumping Scrapy stats: (\{.+$\}).*?$

【讨论】:

  • 把几行日志放到pastebin某处,我看看。
  • 删除组内的$,不删除?。正确的表达式是:^.*\[scrapy\.statscollectors] INFO: Dumping Scrapy stats: (\{.+\}).*$
  • mul_line_json = re.compile('^.*[scrapy\.statscollectors] INFO: Dumping Scrapy stats: (\{.+\}).*$', re.MULTILINE) re.findall (mul_line_json, data) 仍然没有输出
  • 我已使用适用于 Pastbin 的代码编辑了我的答案。
【解决方案2】:

使用 JSON 标记器使这项任务变得非常简单和高效,只要您在原始文档中有一个要搜索的锚点,至少可以识别 JSON blob 的开头。这使用json-five 从 HTML 中提取 JSON:

import json5.tokenizer

with open('5f32d5b4e2c432f660e1df44.html') as f:
    document = f.read()

search_for = "window.__INITIAL_STATE__="
i = document.index(search_for)
j = i + len(search_for)
extract_from = document[j:]

tokens = json5.tokenizer.tokenize(extract_from)
stack = []
collected = []
for token in tokens:
    collected.append(token.value)

    if token.type in ('LBRACE', 'LBRACKET'):
        stack.append(token)
    elif token.type in ('RBRACE', 'RBRACKET'):
        stack.pop()

    if not stack:
        break

json_blob = ''.join(collected)

请注意,这说明 JSON 既是复杂类型(对象、列表)又是标量类型。

【讨论】:

    猜你喜欢
    • 2012-05-21
    • 2022-01-05
    • 1970-01-01
    • 2012-07-02
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-26
    相关资源
    最近更新 更多