Я создаю сайт сравнения цен для своего университетского проекта. Я пытаюсь распечатать товары и цены с этого сайта https://www.lotuss.com.my/en/category/fresh-produce?sort=relevance:DESC, но у меня возникла ошибка:
Exception has occurred: TypeError
'NoneType' object is not callable
File "C:\xampp\htdocs\Price\test.py", line 36, in <module>
grocery_items = soup.findall('div', class_='product-grid-item')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object is not callable
Это код:
from bs4 import BeautifulSoup
import requests
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
chrome_options = Options()
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
service = Service(executable_path='C:/chromedriver/chromedriver.exe')
driver = webdriver.Chrome(service=service, options=chrome_options)
# Open the webpage
driver.get('https://www.lotuss.com.my/en/category/fresh-produce?sort=relevance:DESC')
# Wait for the page to fully load
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "iframe"))
)
print("Please solve the CAPTCHA manually in the opened browser window.")
finally:
input("Press Enter after solving the CAPTCHA...")
html_text = driver.page_source
driver.quit()
soup = BeautifulSoup(html_text, 'lxml')
grocery_items = soup.findall('div', class_='product-grid-item')
grocery_price = soup.findall('span', class_='sc-kHxTfl hwpbzy')
print(grocery_items)
print(grocery_price)
🤔 А знаете ли вы, что...
С Python можно создавать кросс-платформенные приложения для Windows, macOS и Linux.
Ошибка вызвана использованием неправильного метода для объекта супа. Метод должен быть find_all
вместо findall
.
Код должен быть таким, как показано ниже:
grocery_items = soup.find_all('div', class_='product-grid-item')
grocery_price = soup.find_all('span', class_='sc-kHxTfl hwpbzy')
Я протестировал ваш код и обнаружил еще несколько проблем. После того, как вы исправите ошибку, указанную в этом вопросе, вы можете заметить, что на консоли ничего не печатается. Сделайте, как показано ниже:
По умолчанию селен не открывает браузер в полноэкранном режиме, иногда это может привести к тому, что элементы будут не видны и не удастся найти все целевые элементы. Следовательно, откройте Chrome в полноэкранном режиме, используя приведенный ниже код:
driver.get('https://www.lotuss.com.my/en/category/fresh-produce?sort=relevance:DESC')
driver.maximize_window()
Последняя строка вашего кода просто печатает HTML.
print(grocery_items)
print(grocery_price)
Вместо этого вам нужно распечатать текстовые значения HTML. Используйте код, как показано ниже:
for item in grocery_items:
print(item.get_text(strip=True))
for price in grocery_price:
print(price.get_text(strip=True))
Ошибка в вашем коде связана с вызовом soup.findall
. Вам придется заменить это вызовом soup.find_all
или, что еще лучше, использовать CSS-селекторы напрямую с BS4 с помощью soup.select
.
Глядя на веб-сайт, кажется, что вы можете использовать внутренний API для прямого получения данных и пропустить анализ HTML из Selenium.
import json
import requests
url = "https://api-o2o.lotuss.com.my/lotuss-mobile-bff/product/v2/products"
headers = {"Accept-Language": "en"}
q = {
"offset": 0,
"limit": 300,
"filter": {
"categoryUrlKey": "fresh-produce",
},
"websiteCode": "malaysia_hy",
}
q = json.dumps(q)
response = requests.get(url, headers=headers, params = {"q": q})
response.raise_for_status()
Вы можете поиграть со значениями предела и смещения, чтобы перебирать разные результаты.
Лучший!