python-soap-json只抓取了一个页面,而没有抓取其他类似的页面

2024-09-28 22:22:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图刮一个营养网站和下面的代码工程

import requests
from bs4 import BeautifulSoup
import json
import re

page = requests.get("https://nutritiondata.self.com/facts/nut-and-seed-products/3071/1")
soup = BeautifulSoup(page.content, 'html.parser')

scripts = soup.find_all("script")
for script in scripts:
    if 'foodNutrients = ' in script.text:
        jsonStr = script.text
        jsonStr = jsonStr.split('foodNutrients =')[-1]
        jsonStr = jsonStr.rsplit('fillSpanValues')[0]
        jsonStr = jsonStr.rsplit(';',1)[0]
        jsonStr = "".join(jsonStr.split())

        valid_json = re.sub(r'([{,:])(\w+)([},:])', r'\1"\2"\3', jsonStr)
        jsonObj = json.loads(valid_json)

# These are in terms of 100 grams. I also calculated for per serving       
g_per_serv = int(jsonObj['FOODSERVING_WEIGHT_1'].split('(')[-1].split('g')[0])

for k, v in jsonObj.items():
    if k == 'NUTRIENT_0':
        conv_v = (float(v)*g_per_serv)/100

        print ('%s : %s (per 100 grams)   |   %s (per serving %s' %(k, round(float(v)), round(float(conv_v)), jsonObj['FOODSERVING_WEIGHT_1']  ))

但当我尝试在同一个域上的其他几乎相同的网页上使用它时,它就没有了。例如,如果我使用

page = requests.get("https://nutritiondata.self.com/facts/vegetables-and-vegetable-products/2383/2")

我得到了错误

Traceback (most recent call last):
  File "scrape_test_2.py", line 20, in <module>
    jsonObj = json.loads(valid_json)
  File "/Users/benjamattesjaroen/anaconda3/lib/python3.7/json/__init__.py", line 348, in loads
    return _default_decoder.decode(s)
  File "/Users/benjamattesjaroen/anaconda3/lib/python3.7/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/Users/benjamattesjaroen/anaconda3/lib/python3.7/json/decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 1 column 5446 (char 5445)

从两个页面的源代码来看,它们在某种意义上看起来是相同的

<script type="text/javascript">
    <!--
    foodNutrients = { NUTRIENT_142: ........

这是被刮掉的部分。你知道吗

我已经看了一整天了,有人知道如何使这两个页面的脚本工作,这里的问题是什么?你知道吗


Tags: inpyimportselfjsonlinescriptrequests
1条回答
网友
1楼 · 发布于 2024-09-28 22:22:14

我将转而使用hjson,它允许不带引号的键,只需提取整个foodNutrient变量并进行解析,而不是一遍遍地操作字符串。你知道吗


您的错误:

目前,由于至少一个源数组中的元素数长度不同,您的正则表达式清理不合适,因此您的操作失败。我们只检查已知的第一个事件。。。你知道吗

在第一个url中,在使用regex清理之前,您有:

aifr:"[ -35, -10 ]"

之后:

"aifr":"[-35,-10]"

在第二步中,从一个不同长度的数组开始:

aifr:"[ 163, 46, 209, 179, 199, 117, 11, 99, 7, 5, 82 ]"

在regex替换之后,而不是:

"aifr":"[ 163, 46, 209, 179, 199, 117, 11, 99, 7, 5, 82 ]"

您有:

"aifr":"[163,"46",209,"179",199,"117",11,"99",7,"5",82]"

即无效的json。没有更好的界限键:值对。你知道吗


果壳:

使用hjson更容易。或者适当地更新regex以处理可变长度数组。你知道吗

import requests, re, hjson

urls = ['https://nutritiondata.self.com/facts/nut-and-seed-products/3071/1','https://nutritiondata.self.com/facts/vegetables-and-vegetable-products/2383/2']

p = re.compile(r'foodNutrients = (.*?);')

with requests.Session() as s:
    for url in urls:
        r = s.get(url)
        jsonObj = hjson.loads(p.findall(r.text)[0])
        serving_weight = jsonObj['FOODSERVING_WEIGHT_1']
        g_per_serv = int(serving_weight.split('(')[-1].split('g')[0])
        nutrient_0 = jsonObj['NUTRIENT_0']
        conv_v = float(nutrient_0)*g_per_serv/100
        print('%s : %s (per 100 grams)   |   %s (per serving %s' %(nutrient_0, round(float(nutrient_0)), round(float(conv_v)), serving_weight))

相关问题 更多 >