Ответ 1
Сайт имеет шесть основных категорий продуктов. Продукты, принадлежащие к подкатегории, также можно найти в основной категории (например, продукты /furniture/furniture/tables
также можно найти в /furniture
), поэтому вам нужно только собирать товары из основных категорий. Вы можете получить ссылки категорий с главной страницы, но было бы проще использовать карту сайта.
url = 'https://www.courts.com.sg/sitemap/'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
cats = soup.select('li.level-0.category > a')[:6]
links = [i['href'] for i in cats]
Как вы уже упоминали, есть несколько ссылок, которые имеют разную структуру, например: /televisions
. Но если вы нажмете ссылку " View All Products
на этой странице, вы будете перенаправлены в /tv-entertainment/vision/television
. Таким образом, вы можете получить все /televisions
rpoducts /tv-entertainment
. Аналогичным образом, продукты в ссылках на бренды можно найти в основных категориях. Например, продукты /asus
можно найти в /computing-mobile
и других категориях.
В приведенном ниже коде собраны продукты из всех основных категорий, поэтому он должен собирать все продукты на сайте.
from bs4 import BeautifulSoup
import requests
url = 'https://www.courts.com.sg/sitemap/'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
cats = soup.select('li.level-0.category > a')[:6]
links = [i['href'] for i in cats]
products = []
for link in links:
link += '?product_list_limit=24'
while link:
r = requests.get(link)
soup = BeautifulSoup(r.text, 'html.parser')
link = (soup.select_one('a.action.next') or {}).get('href')
for elem in soup.select(".product-item-info .product-item-link"):
product = elem.get_text(strip=True)
products += [product]
print(product)
Я увеличил количество продуктов на странице до 24, но этот код занимает много времени, поскольку он собирает продукты из всех основных категорий и их ссылок на страницы. Однако мы могли бы сделать это намного быстрее с использованием потоков.
from bs4 import BeautifulSoup
import requests
from threading import Thread, Lock
from urllib.parse import urlparse, parse_qs
lock = Lock()
threads = 10
products = []
def get_products(link, products):
soup = BeautifulSoup(requests.get(link).text, 'html.parser')
tags = soup.select(".product-item-info .product-item-link")
with lock:
products += [tag.get_text(strip=True) for tag in tags]
print('page:', link, 'items:', len(tags))
url = 'https://www.courts.com.sg/sitemap/'
soup = BeautifulSoup(requests.get(url).text, 'html.parser')
cats = soup.select('li.level-0.category > a')[:6]
links = [i['href'] for i in cats]
for link in links:
link += '?product_list_limit=24'
soup = BeautifulSoup(requests.get(link).text, 'html.parser')
last_page = soup.select_one('a.page.last')['href']
last_page = int(parse_qs(urlparse(last_page).query)['p'][0])
threads_list = []
for i in range(1, last_page + 1):
page = '{}&p={}'.format(link, i)
thread = Thread(target=get_products, args=(page, products))
thread.start()
threads_list += [thread]
if i % threads == 0 or i == last_page:
for t in threads_list:
t.join()
print(len(products))
print('\n'.join(products))
Этот код собирает 18 466 продуктов с 773 страниц за 5 минут. Я использую 10 потоков, потому что я не хочу слишком сильно подчеркивать сервер, но вы можете использовать больше (большинство серверов могут обрабатывать 20 потоков легко).