我是使用 BeautifulSoup 的新手,因为我想购买 2 个新的 ram 内存,所以我去网上查看很多商店中组件的价格,但我想提取有关价格的所有信息所有产品,如果其中 2 个或更多在同一商店中,请将其保存在 txt 文件中。

这是我使用 https://www,python,html,web-scraping,beautifulsoup"/>

首页 > 解决方案 > Python BeautifulSoup 在没有 id 标签的情况下找不到

我是使用 BeautifulSoup 的新手,因为我想购买 2 个新的 ram 内存,所以我去网上查看很多商店中组件的价格,但我想提取有关价格的所有信息所有产品,如果其中 2 个或更多在同一商店中,请将其保存在 txt 文件中。

这是我使用 https://www

问题描述

我是使用 BeautifulSoup 的新手,因为我想购买 2 个新的 ram 内存,所以我去网上查看很多商店中组件的价格,但我想提取有关价格的所有信息所有产品,如果其中 2 个或更多在同一商店中,请将其保存在 txt 文件中。

这是我使用 https://www.solotodo.cl的页面,所以当我将产品人员添加到 url 时

(例如:https ://www.solotodo.cl/products/66417-kingston-hyperx-fury-black-hx426c16fb38-1-x-8gb-dimm-ddr4-2666 )

并将其放入代码中,当我使用 find_all() 函数时表标签没有出现

  1. hrefs 是所有产品链接的列表
  2. url_base 是第一个 url
for i in hrefs: 
    respond=requests.get(url_base+i)
    sopa=BeautifulSoup(respond.text,'html.parser')
    tabla=soup.find('table',{"class":"table table-sm mb-0"}) 
    print(tabla)

然后当它在控制台中打印时,只显示这些括号 []

所以我想检查一切是否井井有条,我唯一做的就是去父 div 看看我是否可以从那里做点什么,但是当需要通过控制台打印它时,表格的整个部分都做了没有出现

for i in hrefs:
    respond=requests.get(link_base+i)
    sopa=BeautifulSoup(respond.text,'html.parser')
    tabla=sopa.find("div",{"class":"content-card","id":"product-prices-table"}) 
    print(tabla)

这就是我所看到的

<div class="content-card" id="product-prices-table"><div class="d-flex justify-content-end flex-wrap"><div class="mt-2"><butt...

问题是前两个标签之间应该是表格标签,像这样

<div class = "content-card" ...> <table class = "table table-sm mb-0"> < div ...>

所以我的问题:

  • 我应该怎么做才能操纵桌子?使用另一个库?
  • 尝试另一种方式?

解释:

该页面根据页面上的表格动态地发出许多请求以获取该内容。您可以通过计算浏览器正在做什么来重新创建它。

script您可以从初始端点的标签中提取首选商店(ID 和名称)

r = s.get('https://www.solotodo.cl/products/66417-kingston-hyperx-fury-black-hx426c16fb38-1-x-8gb-dimm-ddr4-2666')

data = json.loads(re.search(r'(\{"props.*?)<', r.text).group(1))

store_dict = {i['id']:i['name'] for i in data['props']['pageProps']['preferredCountryStores']}

还要提取产品 id 以供以后使用:

product_id = data['props']['pageProps']['product']['id']

使用这些商店 ID,您可以从 API 请求评级并将它们存储为商店 id:rating 对的字典

ratings_url = f"https://publicapi.solotodo.com/stores/average_ratings/?{''.join([f'&ids={k}' for k in store_dict.keys()])}".replace('?&ids','?ids')

ratings_dict = {i['store'].split('/')[-2]:i['rating'] for i in requests.get(ratings_url).json()}

然后,您可以使用之前的商店 ID 和产品 ID 从 API 检索价格:

prices_url = f'https://publicapi.solotodo.com/products/available_entities/?ids={product_id}' + \
        ''.join([f'&stores={k}' for k in store_dict.keys()])

r = s.get(prices_url).json()

您可以从响应 json 中提取所需的价格信息。

然后,您可以重新创建表格,对没有评级的情况进行一些格式化和处理:

import requests, re, json
import pandas as pd

with requests.Session() as s:
    
    r = s.get('https://www.solotodo.cl/products/66417-kingston-hyperx-fury-black-hx426c16fb38-1-x-8gb-dimm-ddr4-2666')
    
    data = json.loads(re.search(r'(\{"props.*?)<', r.text).group(1))
    
    store_dict = {i['id']:i['name'] for i in data['props']['pageProps']['preferredCountryStores']}

    product_id = data['props']['pageProps']['product']['id']

    ratings_url = f"https://publicapi.solotodo.com/stores/average_ratings/?{''.join([f'&ids={k}' for k in store_dict.keys()])}".replace('?&ids','?ids')

    ratings_dict = {i['store'].split('/')[-2]:i['rating'] for i in requests.get(ratings_url).json()}

    prices_url = f'https://publicapi.solotodo.com/products/available_entities/?ids={product_id}' + \
            ''.join([f'&stores={k}' for k in store_dict.keys()])

    r = s.get(prices_url).json()

tiendas = []
ratings = []
ofertas = []
normales = []

for i in r['results'][0]['entities']:

    tiendas.append(store_dict[int(i['store'].split('/')[-2])])

    try:
        ratings.append(ratings_dict[i['store'].split('/')[-2]])
    except:
        ratings.append('No rating')

    normales.append('{:.3f}'.format(float(i['active_registry']['normal_price'])/1000))
    ofertas.append('{:.3f}'.format(float(i['active_registry']['offer_price'])/1000))

df = pd.DataFrame([tiendas, ratings, ofertas, normales]).T
df.columns = ['Tienda', 'Rating', 'P.Oferta', 'P.Normal']
df.head(5)

样本输出:

在此处输入图像描述


使用 Chrome 开发工具:

您可以按F12在 Chrome 中打开开发工具,按F5刷新您选择的网页,然后在网络选项卡中检查记录的网络活动。

通过这个记录的活动,您可以寻找目标值并确定浏览器在这种特殊情况下如何获取内容。

例子:

在此处输入图像描述

有关以这种方式使用开发工具的更多信息,请参阅12


正则表达式:

在此处输入图像描述

标签: pythonhtmlweb-scrapingbeautifulsoup

解决方案


解释:

该页面根据页面上的表格动态地发出许多请求以获取该内容。您可以通过计算浏览器正在做什么来重新创建它。

script您可以从初始端点的标签中提取首选商店(ID 和名称)

r = s.get('https://www.solotodo.cl/products/66417-kingston-hyperx-fury-black-hx426c16fb38-1-x-8gb-dimm-ddr4-2666')

data = json.loads(re.search(r'(\{"props.*?)<', r.text).group(1))

store_dict = {i['id']:i['name'] for i in data['props']['pageProps']['preferredCountryStores']}

还要提取产品 id 以供以后使用:

product_id = data['props']['pageProps']['product']['id']

使用这些商店 ID,您可以从 API 请求评级并将它们存储为商店 id:rating 对的字典

ratings_url = f"https://publicapi.solotodo.com/stores/average_ratings/?{''.join([f'&ids={k}' for k in store_dict.keys()])}".replace('?&ids','?ids')

ratings_dict = {i['store'].split('/')[-2]:i['rating'] for i in requests.get(ratings_url).json()}

然后,您可以使用之前的商店 ID 和产品 ID 从 API 检索价格:

prices_url = f'https://publicapi.solotodo.com/products/available_entities/?ids={product_id}' + \
        ''.join([f'&stores={k}' for k in store_dict.keys()])

r = s.get(prices_url).json()

您可以从响应 json 中提取所需的价格信息。

然后,您可以重新创建表格,对没有评级的情况进行一些格式化和处理:

import requests, re, json
import pandas as pd

with requests.Session() as s:
    
    r = s.get('https://www.solotodo.cl/products/66417-kingston-hyperx-fury-black-hx426c16fb38-1-x-8gb-dimm-ddr4-2666')
    
    data = json.loads(re.search(r'(\{"props.*?)<', r.text).group(1))
    
    store_dict = {i['id']:i['name'] for i in data['props']['pageProps']['preferredCountryStores']}

    product_id = data['props']['pageProps']['product']['id']

    ratings_url = f"https://publicapi.solotodo.com/stores/average_ratings/?{''.join([f'&ids={k}' for k in store_dict.keys()])}".replace('?&ids','?ids')

    ratings_dict = {i['store'].split('/')[-2]:i['rating'] for i in requests.get(ratings_url).json()}

    prices_url = f'https://publicapi.solotodo.com/products/available_entities/?ids={product_id}' + \
            ''.join([f'&stores={k}' for k in store_dict.keys()])

    r = s.get(prices_url).json()

tiendas = []
ratings = []
ofertas = []
normales = []

for i in r['results'][0]['entities']:

    tiendas.append(store_dict[int(i['store'].split('/')[-2])])

    try:
        ratings.append(ratings_dict[i['store'].split('/')[-2]])
    except:
        ratings.append('No rating')

    normales.append('{:.3f}'.format(float(i['active_registry']['normal_price'])/1000))
    ofertas.append('{:.3f}'.format(float(i['active_registry']['offer_price'])/1000))

df = pd.DataFrame([tiendas, ratings, ofertas, normales]).T
df.columns = ['Tienda', 'Rating', 'P.Oferta', 'P.Normal']
df.head(5)

样本输出:

在此处输入图像描述


使用 Chrome 开发工具:

您可以按F12在 Chrome 中打开开发工具,按F5刷新您选择的网页,然后在网络选项卡中检查记录的网络活动。

通过这个记录的活动,您可以寻找目标值并确定浏览器在这种特殊情况下如何获取内容。

例子:

在此处输入图像描述

有关以这种方式使用开发工具的更多信息,请参阅12


正则表达式:

在此处输入图像描述


推荐阅读