Проблемы с анализом названий продуктов из некоторых ссылок с разной глубиной

Я написал сценарий на python, чтобы перейти на целевую страницу, где каждая категория имеет свои доступные имена на веб-сайте. Мой нижеприведенный скрипт может получить названия продуктов из большинства ссылок (сгенерированных через ссылки категории ровинга, а затем ссылки подкатегории).

Сценарий может анализировать ссылки подкатегорий, выявленные при щелчке + знаке, расположенном рядом с каждой категорией, которые видны на изображении ниже, а затем анализировать все названия продуктов с целевой страницы. Это одна из таких целевых страниц.

Однако некоторые ссылки не имеют такой же глубины, как другие ссылки. Например, эта ссылка и эта отличаются от обычных ссылок, подобных этой.

Как я могу получить все названия продуктов из всех ссылок независимо от их разной глубины?

Это то, что я пробовал до сих пор:

import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup

link = "https://www.courts.com.sg/"

res = requests.get(link)
soup = BeautifulSoup(res.text,"lxml")
for item in soup.select(".nav-dropdown li a"):
    if "#" in item.get("href"):continue  #kick out invalid links
    newlink = urljoin(link,item.get("href"))
    req = requests.get(newlink)
    sauce = BeautifulSoup(req.text,"lxml")
    for elem in sauce.select(".product-item-info .product-item-link"):
        print(elem.get_text(strip=True))

Как найти ссылки на trget:

enter image description here

Ответ 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 потоков легко).

Ответ 2

Я бы посоветовал начать очищать со страниц sitemap

Найдено здесь

Если они должны были добавить продукты, они, вероятно, также появятся здесь.

Ответ 3

Поскольку ваша основная проблема заключается в поиске ссылок, вот генератор, который найдет все ссылки категории и подкатегории, используя карту сайта krflol, указанную в его решении:

from bs4 import BeautifulSoup
import requests


def category_urls():
    response = requests.get('https://www.courts.com.sg/sitemap')
    html_soup = BeautifulSoup(response.text, features='html.parser')
    categories_sitemap = html_soup.find(attrs={'class': 'xsitemap-categories'})

    for category_a_tag in categories_sitemap.find_all('a'):
        yield category_a_tag.attrs['href']

И чтобы найти имена продуктов, просто очистите каждую из полученных category_urls.

Ответ 4

Я видел веб-сайт для разбора и обнаружил, что все продукты доступны в нижней левой части главной страницы https://www.courts.com.sg/. После нажатия на один из них мы переходим на первую страницу рекламы конкретного категория. Где мы должны войти в список "Все продукты для его получения".

Ниже приведен код целиком:

import requests
from bs4 import BeautifulSoup

def parser():
    parsing_list = []
    url = 'https://www.courts.com.sg/'
    source_code = requests.get(url)
    plain_text = source_code.text
    soup = BeautifulSoup(plain_text, "html.parser")
    ul = soup.find('footer',{'class':'page-footer'}).find('ul')
    for l in ul.find_all('li'):
        nextlink = url + l.find('a').get('href')
        response = requests.get(nextlink)
        inner_soup = BeautifulSoup(response.text, "html.parser")
        parsing_list.append(url + inner_soup.find('div',{'class':'category-static-links ng-scope'}).find('a').get('href'))
return parsing_list

Эта функция вернет список всех продуктов всех категорий, которые ваш код не очистил от него.