Karol
Karol

Reputation: 15

How to scrape substring from elements class names?

While scraping product info from website I like to extract substring from class names of following element.

<li class="product type-product post-77078 status-publish first outofstock product_cat-lozyska taxable shipping-taxable purchasable product-type-simple">

I would like to scrape 'product_cat-lozyska', but this part can be different due to lots of records, for example 'product_cat-uszczelnienia' (bold part is always there). I want to scrape all of these product_cat-'s.

Example of code with scraping other things from HTML:

products = soup.find('ul', {'class':re.compile('^products')}).find_all('li')

    
for product in products:
    try:
        productName = product.find('span',{'class':'sku'}).text
    except:
        productName = 'none'

Based on this structure:

Upvotes: 0

Views: 862

Answers (3)

HedgeHog
HedgeHog

Reputation: 25048

In case you like to scrape all the class names that starts with product_cat- you could do that with following comprehension - It iterates over your products, pick the values of class as list, iterate it and only return these names that startswith() your pattern.

Note: comprehension is based on a set, so you will avoid duplicate class names:

set(c.split('product_cat-')[-1] for p in products for c in p.get('class') if c.startswith('product_cat-'))
#output
{'pasy-napedowe', 'uszczelnienia-hydrauliki-silowej', 'lozyska', 'lancuchy-i-kola-lancuchowe', 'uncategorized'}

Including above approach in to your process, to get class information for each product, you could use next() to iterate the class names:

cat = next(c.split('product_cat-')[-1] for c in product.get('class') if c.startswith('product_cat-'))

Example

...
products = soup.find('ul', {'class':re.compile('^products')}).find_all('li')

data = []

for product in products:
    try:
        productName = product.find('span',{'class':'sku'}).text
    except:
        productName = 'none'

    try:
        cat = next(c.split('product_cat-')[-1] for c in product.get('class') if c.startswith('product_cat-'))
    except:
        cat = 'none'

    data.append({
        'productName':productName,
        'cat':cat
    })
df = pd.DataFrame(data)
df.to_csv('products.csv', index=False)

Output

productName cat
ZZ 901054 VAY uszczelnienia-hydrauliki-silowej
ZZ 851005 VAY uszczelnienia-hydrauliki-silowej
ZZ 80954 VAY uszczelnienia-hydrauliki-silowej
ZZ 75904 VAY uszczelnienia-hydrauliki-silowej
ZZ 70854 VAY uszczelnienia-hydrauliki-silowej
ZZ 65805 VAY uszczelnienia-hydrauliki-silowej
ZZ 65804 VAY uszczelnienia-hydrauliki-silowej
ZZ 60755 VAY uszczelnienia-hydrauliki-silowej
ZZ 55654 VAY uszczelnienia-hydrauliki-silowej
ZZ 50604 VAY uszczelnienia-hydrauliki-silowej
ZZ 45554 VAY uszczelnienia-hydrauliki-silowej
ZZ 40504 VAY uszczelnienia-hydrauliki-silowej
ZZ 35454 VAY uszczelnienia-hydrauliki-silowej
ZZ 30404 VAY uszczelnienia-hydrauliki-silowej
XPA 710 CT pasy-napedowe
UCP 202 KBF lozyska
U298/U291 SET9 lozyska

Upvotes: 0

Andrej Kesely
Andrej Kesely

Reputation: 195408

To get info about all SKU you can use next example (just iterate over elements of class="product"):

import requests
import pandas as pd
from bs4 import BeautifulSoup


url = "https://specjal.com/sklep/"
soup = BeautifulSoup(requests.get(url).content, "html.parser")

all_data = []
for p in soup.select(".product"):
    price = p.select_one(".price-intax")
    stock = p.select_one(".in-stock, .out-of-stock")

    all_data.append(
        {
            "sku": p.select_one(".sku").text,
            "title": p.select_one(".woocommerce-loop-product__title").text,
            "link": p.select_one(".woocommerce-loop-product__link")["href"],
            "stock": stock.text,
            "price": price.text if price else "-",
        }
    )

df = pd.DataFrame(all_data)
print(df)
df.to_csv("data.csv", index=False)

Prints:

                     sku                                      title                                                               link         stock          price
0        ZZ 90*105*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1064/   10 in stock   14.86zł/szt.
1        ZZ 85*100*5 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1063/   10 in stock   13.76zł/szt.
2         ZZ 80*95*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1062/   20 in stock   12.66zł/szt.
3         ZZ 75*90*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1061/   20 in stock   11.01zł/szt.
4         ZZ 70*85*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1060/   20 in stock    9.91zł/szt.
5         ZZ 65*80*5 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1059/   20 in stock    9.36zł/szt.
6         ZZ 65*80*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1058/   20 in stock    9.36zł/szt.
7         ZZ 60*75*5 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1057/   14 in stock    8.25zł/szt.
8         ZZ 55*65*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1056/   10 in stock    7.71zł/szt.
9         ZZ 50*60*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1055/   20 in stock    6.61zł/szt.
10        ZZ 45*55*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1054/   20 in stock    6.05zł/szt.
11        ZZ 40*50*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1053/   17 in stock    5.39zł/szt.
12        ZZ 35*45*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1052/   30 in stock     4.8zł/szt.
13        ZZ 30*40*4 VAY              uszczelnienie techniczne  NBR     https://specjal.com/produkt/uszczelnienie-techniczne-nbr-1051/   20 in stock    4.26zł/szt.
14            XPA 710 CT                     Pas klinowy  CONTITECH             https://specjal.com/produkt/pas-klinowy-contitech-518/  Out of stock   39.61zł/szt.
15           UCP 202 KBF             Łożysko samonastawne z obudową     https://specjal.com/produkt/lozysko-samonastawne-z-obudowa-68/  Out of stock    19.7zł/szt.

...

and saves data.csv (screenshot from LibreOffice):

enter image description here

Upvotes: 1

Arshia Moghaddam
Arshia Moghaddam

Reputation: 538

You could use a lambda function and use startsWith function, like so:

products = soup.findAll("li", {"class" : lambda L: L and L.startswith('product_cat-')})

or alternatively use regular expression, like the following:

products = soup.findAll("li", {"class" : re.compile('product_cat-.*')})

Upvotes: 0

Related Questions