Home > Software engineering >  Web-scraping with Python to extract microdata for each page from a sitemap.xml
Web-scraping with Python to extract microdata for each page from a sitemap.xml

Time:02-25

I'm trying to extract name, brand, prices, stock microdata from pages extracted from sitemap.xml But I'm blocked with the following step, thank you for helping me as I'm a newbie I can't understand the blocking element

  • Scrape the sitemap.xml to have list of urls : OK
  • Extract the metadata : OK
  • Extract the product schema : OK
  • Extract the products not OK
  • Crawl the site and store the products not OK

  • Scrape the sitemap.xml to have list of urls : OK
import pandas as pd
import requests
import extruct
from w3lib.html import get_base_url
import urllib.request
from urllib.parse import urlparse
from bs4 import BeautifulSoup
import advertools as adv
proximus_sitemap = adv.sitemap_to_df('https://www.proximus.be/iportal/sitemap.xml')
proximus_sitemap = proximus_sitemap[proximus_sitemap['loc'].str.contains('boutique')]
proximus_sitemap = proximus_sitemap[proximus_sitemap['loc'].str.contains('/fr/')]
  • Extract the metadata : OK
def extract_metadata(url):
 
    r = requests.get(url)
    base_url = get_base_url(r.text, r.url)
    metadata = extruct.extract(r.text, 
                               base_url=base_url,
                               uniform=True,
                               syntaxes=['json-ld',
                                         'microdata',
                                         'opengraph'])
    return metadata
metadata = extract_metadata('https://www.proximus.be/fr/id_cr_apple-iphone-13-128gb-blue/particuliers/equipement/boutique/apple-iphone-13-128gb-blue.html')
metadata
  • Extract the product schema : OK
def get_dictionary_by_key_value(dictionary, target_key, target_value):
    for key in dictionary:
        if len(dictionary[key]) > 0:
            for item in dictionary[key]:
                if item[target_key] == target_value:
                    return item
Product = get_dictionary_by_key_value(metadata, "@type", "Product")
Product
  • Extract the products not OK => errormessage = errorkey 'offers'
def get_products(metadata):
 
    
    Product = get_dictionary_by_key_value(metadata, "@type", "Product")

    if Product:
    
        products = []

        for offer in Product['offers']['offers']:
            product = {
                'product_name': Product.get('name', ''),
                'brand': offer.get('description', ''),
                'availability': offer.get('availability', ''),
                'lowprice': offer.get('lowPrice', ''),
                'highprice': offer.get('highPrice', ''),
                'price': offer.get('price', ''),
                'priceCurrency': offer.get('priceCurrency', ''),
            }

            products.append(product)

        return products
  • Crawl the site and store the products not OK as blocked during previous step
def scrape_products(proximus_sitemap, url='url'):
 

    df_products = pd.DataFrame(columns = ['product_name', 'brand', 'name', 'availability', 
                                          'lowprice', 'highprice','price','priceCurrency'])

    for index, row in proximus_sitemap.iterrows(): 
        
        metadata = extract_metadata(row[url])          
        products = get_products(metadata)
        
        if products is not None:
            for product in products:             
                df_products = df_products.append(product, ignore_index=True)

    return df_products
df_products = scrape_products(proximus_sitemap, url='loc')
df_products.to_csv('patch.csv', index=False)
df_products.head()

CodePudding user response:

You can simply continue by using the advertools SEO crawler. It has a crawl function that also extracts structured data by default (JSON-LD, OpenGraph, and Twitter).

I tried to crawl a sample of ten pages, and this what the output looks like:

adv.crawl(proximus_sitemap['loc'], 'proximums.jl') 
proximus_crawl = pd.read_json('proximums.jl', lines=True)
proximus_crawl.filter(regex='jsonld').columns

Index(['jsonld_@context', 'jsonld_@type', 'jsonld_name', 'jsonld_url',
       'jsonld_potentialAction.@type', 'jsonld_potentialAction.target',
       'jsonld_potentialAction.query-input', 'jsonld_1_@context',
       'jsonld_1_@type', 'jsonld_1_name', 'jsonld_1_url', 'jsonld_1_logo',
       'jsonld_1_sameAs', 'jsonld_2_@context', 'jsonld_2_@type',
       'jsonld_2_itemListElement', 'jsonld_2_name', 'jsonld_2_image',
       'jsonld_2_description', 'jsonld_2_sku', 'jsonld_2_review',
       'jsonld_2_brand.@type', 'jsonld_2_brand.name',
       'jsonld_2_aggregateRating.@type',
       'jsonld_2_aggregateRating.ratingValue',
       'jsonld_2_aggregateRating.reviewCount', 'jsonld_2_offers.@type',
       'jsonld_2_offers.priceCurrency', 'jsonld_2_offers.availability',
       'jsonld_2_offers.price', 'jsonld_3_@context', 'jsonld_3_@type',
       'jsonld_3_itemListElement', 'jsonld_image', 'jsonld_description',
       'jsonld_sku', 'jsonld_review', 'jsonld_brand.@type',
       'jsonld_brand.name', 'jsonld_aggregateRating.@type',
       'jsonld_aggregateRating.ratingValue',
       'jsonld_aggregateRating.reviewCount', 'jsonld_offers.@type',
       'jsonld_offers.lowPrice', 'jsonld_offers.highPrice',
       'jsonld_offers.priceCurrency', 'jsonld_offers.availability',
       'jsonld_offers.price', 'jsonld_offers.offerCount',
       'jsonld_1_itemListElement', 'jsonld_2_offers.lowPrice',
       'jsonld_2_offers.highPrice', 'jsonld_2_offers.offerCount',
       'jsonld_itemListElement'],
      dtype='object')

These are some of the columns you might be interested in (containing price, currency, availability, etc.)

jsonld_2_description jsonld_2_offers.priceCurrency jsonld_2_offers.availability jsonld_2_offers.price jsonld_description jsonld_offers.lowPrice jsonld_offers.priceCurrency jsonld_offers.availability jsonld_offers.price jsonld_2_offers.lowPrice
0 nan nan nan nan nan nan nan nan nan nan
1 Numéro 7 EUR OutOfStock 369.99 nan nan nan nan nan nan
2 nan nan nan nan Apple 81.82 EUR InStock 487.6 nan
3 nan nan nan nan nan nan nan nan nan nan
4 nan nan nan nan Huawei nan EUR OutOfStock 330.57 nan
5 nan nan nan nan Apple 81.82 EUR LimitedAvailability 487.6 nan
6 Apple EUR InStock 589.99 nan nan nan nan nan 99
7 Apple EUR LimitedAvailability 589.99 nan nan nan nan nan 99
8 nan nan nan nan nan nan nan nan nan nan
9 nan nan nan nan nan nan nan nan nan nan
  • Related