3 votes

Erreur dans python web scraper ne fonctionne pas correctement

from urllib.request import urlopen as uReq
from bs4 import BeautifulSoup as soup

my_url = 'https://www.newegg.com/Video-Cards-Video-Devices/Category/ID-38?Tpk=graphics%20cards'

# opening up connection, grabbing the page
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()

#html parsing
page_soup = soup(page_html, "html.parser")

#grabs each product
containers =  page_soup.findAll("div", {"class":"item-container"})

for container in containers:
    brand = container[0].img["title"].title()

    title_container = container.findAll("a", {"class":"item-title"})
    product_name = title_container[0].txt

    shipping_container = container.findAll("li", {"class":"price-ship"})
    shipping = shipping_container[0].text.strip()

    print("Brand: "+ brand)
    print("product name: "+ product_name)
    print("shipping: "+ shipping)

Après avoir exécuté ce programme, il me donne les erreurs suivantes.

Traceback (dernier appel le plus récent) : Fichier "my_first_websraper.py", ligne 18, dans brand = container[0].img["title"].title() Fichier " C:\Users\MyUserName\AppData\Local\Programs\Python\Python38 -32 \lib\site -packages \bs4\element.py ", ligne 1368, dans getitem return self.attrs[key] KeyError : 0

Lorsqu'il l'exécute dans le didacticiel, non seulement tout est répertorié correctement, mais tout est répertorié de la même manière sur le site Web. Avez-vous des idées sur la façon de résoudre ce problème ?

Pour avoir une idée de ce à quoi cela devrait ressembler, allez à 28:55 sur cette vidéo : https://www.youtube.com/watch?v=XQgXKtPSzUI

1voto

bherbruck Points 1821

Je sais que je n'utilise pas les mêmes paquets ni même le même code que vous, mais j'ai pu obtenir chaque article et son prix en utilisant Selenium ! J'ai eu des problèmes avec d'autres bibliothèques car elles ne récupèrent que le contenu html et ne peuvent pas gérer les navigateurs sans tête (en général). Cela cause des problèmes avec les pages web rendues parce qu'ils obtiennent la page avant que tous les produits soient rendus.

J'ai obtenu les prix sur la page avec ce script de selenium :

EDIT : ajout du triage

EDIT : ajout de la sortie excel et du formatage des chiffres

url = "https://www.newegg.com/Video-Cards-Video-Devices/Category/ID-38?Tpk=graphics%20cards"

driver.get(url)

# let the page load
time.sleep(5)

get_price = lambda x: x.text.split(' ')[0].replace('$', '').replace('Free', '0')

# get all the prices of the products on the page
prices = [{'product': item.find_element_by_class_name('item-title').text,
           'price': get_price(item.find_element_by_class_name('price-current')),
           'shipping': get_price(item.find_element_by_class_name('price-ship'))}
          for item in driver.find_elements_by_class_name('item-info')]

prices_sorted = sorted(prices, key=lambda x: x['price'])

# prettify the output with json
import json
print(json.dumps(prices_sorted, indent=4))

# -------------- export to excel --------------
from openpyxl import Workbook

 # create the workbook
wb = Workbook()

# select the first sheet
ws = wb.active
# write the header row
ws.append([key for key in prices_sorted[0].keys()])
for row in prices_sorted:
    # write each row
    ws.append([value for value in row.values()])

path = './prices.xlsx'
# save the file
wb.save(filename = path)

Sortie :

[
    {
        "product": "GIGABYTE Radeon RX 570 DirectX 12 GV-RX570GAMING-4GD REV2.0 Video Card",
        "price": "$119.99",
        "shipping": "Free"
    },
    {
        "product": "ASRock Phantom Gaming D Radeon RX 570 DirectX 12 RX570 4G Video Card",
        "price": "$119.99",
        "shipping": "Free"
    },
    {
        "product": "MSI Radeon RX 570 DirectX 12 RX 570 8GT OC Video Card",
        "price": "$135.99",
        "shipping": "Free"
    },
    {
        "product": "XFX Radeon RX 580 DirectX 12 RX-580P8RFD6 Video Card",
        "price": "$189.99",
        "shipping": "$5.99"
    },
    {
        "product": "MSI GeForce GTX 1660 SUPER DirectX 12 GTX 1660 SUPER VENTUS XS OC Video Card",
        "price": "$249.99",
        "shipping": "Free"
    },
    {
        "product": "SAPPHIRE PULSE Radeon RX 5600 XT DirectX 12 100419P6GL Video Card",
        "price": "$289.99",
        "shipping": "$3.99"
    },
    {
        "product": "EVGA GeForce GTX 1660 Ti SC ULTRA GAMING, 06G-P4-1667-KR, 6GB GDDR6, Dual Fan, Metal Backplate",
        "price": "$299.99",
        "shipping": "Free"
    },
    {
        "product": "EVGA GeForce RTX 2060 KO ULTRA GAMING Video Card, 06G-P4-2068-KR, 6GB GDDR6, Dual Fans, Metal Backplate",
        "price": "$319.99",
        "shipping": "Free"
    },
    {
        "product": "MSI GeForce RTX 2060 DirectX 12 RTX 2060 VENTUS XS 6G OC Video Card",
        "price": "$339.99",
        "shipping": "Free"
    },
    {
        "product": "ASUS GeForce RTX 2060 Overclocked 6G GDDR6 Dual-Fan EVO Edition Graphics Card (DUAL-RTX2060-O6G-EVO)",
        "price": "$349.99",
        "shipping": "Free"
    },
    {
        "product": "ASUS ROG Strix Radeon RX 5700 XT ROG-STRIX-RX5700XT-O8G-GAMING Video Card",
        "price": "$459.99",
        "shipping": "Free"
    },
    {
        "product": "GIGABYTE GeForce RTX 2070 Super WINDFORCE OC 3X 8G Graphics Card, GV-N207SWF3OC-8GD",
        "price": "$499.99",
        "shipping": "Free"
    }
]

Sortie Excel :

enter image description here

Voici un lien vers la fiche Colab pour que vous puissiez l'exécuter vous-même : https://drive.google.com/open?id=1LLTyZ0ATiUS3f-WJdGvnlaUXv0h8U4i-

0voto

Johnny Points 211

Si vous faites défiler la vidéo YouTube jusqu'au commentaire du haut, l'auteur explique le problème.

Il ne semble pas que container.div vous donnera le div du item-info mais plutôt le div de la classe item-badges classe. En effet, cette dernière intervient avant la première. Lorsque vous accédez à une balise avec le point( . ), il retournera simplement la première instance de cette balise, comme c'est le cas ici.

Pour résoudre ce problème, utilisez le find() pour trouver la division exacte qui contient l'information que vous voulez.

exemple : divWithInfo = containers[0].find("div", "item-info")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X