python - 无法从一些不同深度的链接中解析产品名称

标签 python python-3.x web-scraping beautifulsoup

我用 python 编写了一个脚本以到达目标页面,其中每个类别在网站中都有其可用的项目名称。我下面的脚本可以从大多数链接中获取产品名称(通过流动类别链接和子类别链接生成)。

该脚本可以解析单击位于每个类别旁边的 + 符号时显示的子类别链接,如下图所示,然后解析目标页面中的所有产品名称。 This is one of such目标页面。

However, few of the links do not have the same depth as other links. For example this link and this one are different from usual links like this one.

如何从所有链接中获取所有产品名称,而不管它们的深度如何?

这是我到目前为止尝试过的:

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

最佳答案

该网站有六个主要产品类别。属于子类别的产品也可以在主类别中找到(例如 /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。因此,您可以从 /tv-entertainment 获取所有 /televisions 产品。同样,品牌链接中的产品可以在主要类别中找到。例如,/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 个,但这段代码仍然需要花费大量时间,因为它收集了所有主要类别的产品及其分页链接。但是,我们可以使用 threads 使其更快.

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))

此代码在大约 5 分钟内从 773 个页面收集了 18,466 种产品。我使用 10 个线程是因为我不想给服务器带来太多压力,但您可以使用更多线程(大多数服务器可以轻松处理 20 个线程)。

关于python - 无法从一些不同深度的链接中解析产品名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52065009/

相关文章:

python - Gunicorn 通过导致 404 导致 Flask 的 add_url_rule

python - 生成每个数字 0..k 的随机矩阵

mysql - PostgreSQL 多个 CSV 导入并向每列添加文件名

python - 在网站中抓取动态内容

Python套接字.错误: [Errno 113] No route to host but ping works

python - 等轴 Bokeh 图

python - 如何在不覆盖 `self` 的情况下模拟基于类的 View 的特定方法?

python-3.x - 如果包含字符串列表,则过滤 pyspark 数据框

python - 如何修复 BeautifulSoup 中的 'KeyError' 错误

使用 selenium : ui-dialog trouble with switching 进行 Python 3 网页抓取