【问题标题】:How to convert response.text to json in Scrapy如何在 Scrapy 中将 response.text 转换为 json
【发布时间】:2018-11-19 15:10:00
【问题描述】:

我正在使用 Scrapy 从以下链接中抓取财务数据:

Financial Data from Tencent

reponse.body 如下:

我尝试使用常规回归拆分响应,然后将其转换为 json,但它没有显示 json 对象,这是我的代码:

import scrapy
import re
import json

class StocksSpider(scrapy.Spider):
    name = 'stocks'
    allowed_domains = ['web.ifzq.gtimg.cn']
    start_urls = ['http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_callback=jQuery11240339550$']

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url=url, callback=self.parse,
            #endpoint='render.json', # optional; default is render.html
            #splash_url='<url>',     # optional; overrides SPLASH_URL
            #slot_policy=scrapy_splash.SlotPolicy.PER_DOMAIN,  # optional
            )

    def parse(self, response):
        try:
            json_data = re.search('\{\"data\"\:(.+?)\}\}\]', response.text).group(1)
        except AttributeError:
            json_data = ''
        #print json_data
        loaded_json = json.loads(json_data)

        print loaded_json


它抛出一个错误说没有json对象可以被解码:

    Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/scrapy/utils/defer.py", line 102, in iter_errback
    yield next(it)
  File "/usr/local/lib/python2.7/dist-packages/scrapy_splash/middleware.py", line 156, in process_spider_output
    for el in result:
  File "/usr/local/lib/python2.7/dist-packages/scrapy/spidermiddlewares/offsite.py", line 30, in process_spider_output
    for x in result:
  File "/usr/local/lib/python2.7/dist-packages/scrapy/spidermiddlewares/referer.py", line 339, in <genexpr>
    return (_set_referer(r) for r in result or ())
  File "/usr/local/lib/python2.7/dist-packages/scrapy/spidermiddlewares/urllength.py", line 37, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "/usr/local/lib/python2.7/dist-packages/scrapy/spidermiddlewares/depth.py", line 58, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "/root/finance/finance/spiders/stocks.py", line 25, in parse
    loaded_json = json.loads(json_data)
  File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.7/json/decoder.py", line 382, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded
2018-06-09 23:54:26 [scrapy.core.engine] INFO: Closing spider (finished)

我的目标是将其转换为 json,以便我可以轻松地迭代内容。 是否有必要将其转换为 json 以及在这种情况下如何转换?响应是 unicode 格式,所以我也需要将其转换为 utf-8?有没有其他好的迭代方式?

【问题讨论】:

  • 是否需要 url (&amp;_callback=jQuery1124033955090772971586_1528569153921) 中的最后一个参数?没有它返回的数据看起来很相似,并且是一个有效的 json。
  • 我不知道,我是 Python 和 Scrapy 的新手。源数据的链接是从这个网站找到的:gu.qq.com/hk00001/gp/income我用谷歌浏览器->Inspect->Source找到那个链接

标签: python json unicode web-scraping scrapy


【解决方案1】:
import re
import scrapy


class StocksSpider(scrapy.Spider):
    name = 'stocks'
    allowed_domains = ['gtimg.cn']
    start_urls = ['http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_callback=jQuery1124033955090772971586_1528569153921&_=1528569153953']

    def parse(self, response):
        try:
            json = eval(re.findall(r'jQuery\d+_\d+(\(\{.+\}\))', response.body)[0])
            print json
        except:
            self.log('Response couldn\'t be parsed, seems like it is having different format')

不要在 json 中转换,而是使用 eval,因为最后你将把它用作列表等的字典

可能是这样的,

import re
import scrapy


class StocksSpider(scrapy.Spider):
    name = 'stocks'
    allowed_domains = ['gtimg.cn']
    start_urls = ['http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_callback=jQuery1124033955090772971586_1528569153921&_=1528569153953']

    def parse(self, response):
        data = eval(re.findall(r'jQuery\d+_\d+(\(\{.+\}\))', response.body)[0])
        items = data.get('data', {}).get('data', [])

        for item in items:
            yield item

或者你可以使用 json load 代替 eval 也可以

【讨论】:

  • 非常感谢您的帮助 Yash,第一种方法可以生成非常简洁的 'json-like' 响应。第二种方法,生成提取的值,如果导出为 csv,则存储整齐,但有几行以 json 格式存储。用了一下午的时间测试迭代,推送数据到 MySQL 服务器,但没有成功,不知道是我的代码问题还是从 Scrapy 提取的 json 的问题。
  • @NicholasKan 还有什么可以帮助你的吗?
  • 如果你能帮助测试我的代码,看看为什么我不能遍历生成的 json/为什么它没有发布到 MySQL 服务器?
  • 我可以通过电子邮件发送给您吗?
  • 刚刚发送,请查收邮件
【解决方案2】:

问题似乎是实际数据在jQuery1124033955090772971586_1528569153921() 内。我可以通过删除请求 url 中的参数来摆脱它。如果您绝对需要它,这可能会奏效:

>>> import json
>>> url = 'http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_callback=jQuery1124033955090772971586_1528569153921&_=1528569153953'
>>> fetch(url)
2018-06-09 21:55:13 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_callback=jQuery1124033955090772971586_1528569153921&_=1528569153953> (referer: None)
>>> data = response.text.strip('jQuery1124033955090772971586_1528569153921()')
>>> parsed_data = json.loads(data)

如果您希望从 url 中删除 _callback 参数,只需:

>>> import json
>>> url = 'http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_=1528569153953'
>>> fetch(url)
2018-06-09 21:53:36 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_=1528569153953> (referer: None)
>>> parsed_data = json.loads(response.text)

【讨论】:

  • 嗨 bla,这两种方法对我来说都可以,谢谢你的回答,现在进入我的问题的第二部分,scrapy 响应是 unicode 格式,因此打印结果:{u'msg' : u'', u'code': 0, u'data': {u'data': [{u'fd_administration_fee_ratio': u'--', u'fd_repdate_ratio': u'0.05', u'fd_profit_after_share_ratio' : u'--', u'fd_stock_dividend': u'10340.00', u'fd_administration_fee': u'0.00', u'fd_depreciation': u'-13262.00', u'fd_dividend_base_share': u'2.68', u' fd_profit_before_tax_ratio': u'-1.69......你知道如何通过去掉'u'将其转换为原生json吗?
  • 不客气,:)。处理以u 开头的字符串应该不会有问题(请查看this response 了解更多信息)。如果您真的想摆脱它,请尝试解析response.tex.encode('utf8')(文档here)。如果可能,也尝试使用 python3。 :)
  • 您好,与原始数据相比,我发现您的答案不起作用。原始数据中记录应该是从'fd_year'开始的,但是改成你的代码后,它是从管理费开始的',请你看看这个?
  • json.loads 不断返回 unicode 编码的字符串,即使源不是一个。最简单的解决方案是根据解析器返回的字典创建自己的字典:{k.encode('utf8'):v.encode('utf8') for k, v in json.loads(data).items()}
  • 很遗憾听到这个消息。能否提供更多有关问题所在的信息?
【解决方案3】:

正如 bla 所说,没有 &_callback=jQuery1124033955090772971586_1528569153921 数据是有效的 json,不需要回调也不是静态的,例如 http://web.ifzq.gtimg.cn/appstock/hk/HkInfo/getFinReport?type=3&reporttime_type=1&code=00001&startyear=1990&endyear=2016&_callback=test 给出相同的结果

【讨论】:

  • 响应不是原生 json,因此我不知道如何迭代它。
猜你喜欢
  • 2020-03-10
  • 2017-04-18
  • 2015-06-21
  • 1970-01-01
  • 2018-12-29
  • 2020-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多