Web Scraping Amazon con Scrapy

raspado amazon

1. ¿Qué es Scrapy CrawlSpider?

CrawlSpider es una clase derivada de Scrapy, y el principio de diseño de la clase Spider es rastrear sólo las páginas web de la lista start_url. Por el contrario, la clase CrawlSpider define algunas reglas para proporcionar un mecanismo conveniente para el seguimiento de enlaces - extracción de enlaces de raspado Amazon páginas web y continuar el rastreo.

CrawlSpider puede emparejar URLs que cumplan ciertas condiciones, ensamblarlas en objetos Request, y enviarlas automáticamente al motor mientras se especifica una función callback. En otras palabras, el rastreador CrawlSpider puede recuperar automáticamente conexiones de acuerdo con reglas predefinidas.

2. Creación de una araña CrawlSpider para el scraping de Amazon

scrapy genspider -t crawl spider_nombre dominio_nombre

Crear comando Scraping Amazon crawler:

Por ejemplo, para crear un rastreador de Amazon llamado "amazonTop":

scrapy genspider -t crawl amzonTop amazon.com

Las siguientes palabras son todo el código:

importar scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class TSpider(CrawlSpider):
    name = 'amzonTop '
    dominios_permitidos = ['amazon.com']
    start_urls = ['https://amazon.com/']

    rules = (
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        item = {}
        # item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
        # item['name'] = response.xpath('//div[@id="name"]').get()
        # item['description'] = response.xpath('//div[@id="description"]').get()
        devolver item

Rules es una tupla o lista que contiene objetos Rule. Una regla consta de parámetros como LinkExtractor, callback y follow.

A. LinkExtractor: Extractor de enlaces que compara direcciones URL mediante regex, XPath o CSS.

B. devolución de llamada: Una función de devolución de llamada para las direcciones URL extraídas, opcional.

C. seguir: Indica si las respuestas correspondientes a las direcciones URL extraídas seguirán siendo procesadas por las reglas. Verdadero significa que lo harán, y Falso significa que no lo harán.

3. Extracción de datos de productos de Amazon

3.1 Crear un crawler de Scraping Amazon

scrapy genspider -t crawl amazonTop2 amazon.com

La estructura del Código Araña:

3.2 Extraer las URL para paginar la lista de productos y los detalles de los productos.

A. Extraer todos los Asin y rangos de productos de la página de lista de productos, es decir, recuperar los Asin y rangos de los cajas azules en la imagen.

B. Extraer Asin para todos los colores y especificaciones de la página de detalles del producto, es decir, recuperar Asin del cajas verdesque incluyen a Asin de las cajas azules.

Las cajas verdes: Como las tallas X, M, L, XL y XXL para la ropa en los sitios de compras.

Archivo araña: amzonTop2.py

importar datetime
importar re
import time
from copy import deepcopy

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class Amazontop2Spider(CrawlSpider):
    name = 'amazonTop2'
    dominios_permitidos = ['amazon.com']
    # https://www.amazon.com/Best-Sellers-Tools-Home-Improvement-Wallpaper/zgbs/hi/2242314011/ref=zg_bs_pg_2?_encoding=UTF8&pg=1
    start_urls = ['https://amazon.com/Best-Sellers-Tools-Home-Improvement-Wallpaper/zgbs/hi/2242314011/ref=zg_bs_pg_2']
    
    reglas = [
        Rule(LinkExtractor(restrict_css=('.a-selected','.a-normal')), callback='parse_item', follow=True),
    ]

    def parse_item(self, response):
        asin_list_str = "".join(response.xpath('//div[@class="p13n-desktop-grid"]/@data-client-recs-list').extract())
        if asin_list_str:
            asin_list = eval(asin_list_str)
            para asinDict en asin_list:
                item = {}
                if "'id'" in str(asinDict):
                    listProAsin = asinDict['id']
                    pro_rank = asinDict['metadataMap']['render.zg.rank']
                    item['rango'] = pro_rank
                    item['ListaAsin'] = listaProAsin
                   
                    item['rankAsinUrl'] =f "https://www.amazon.com/Textile-Decorative-Striped-Corduroy-Pillowcases/dp/{listProAsin}/ref=zg_bs_3732341_sccl_1/136-3072892-8658650?psc=1"

                    print("-"*30)
                    print(item)
                    print('-'*30)
                    yield scrapy.Request(item["rankAsinUrl"], callback=self.parse_list_asin,
                                         meta={"main_info": deepcopy(item)})


    def parse_list_asin(self, response):
        """
        
        :param respuesta:
        :return:
        """
        news_info = response.meta["main_info"]
        list_ASIN_all_findall = re.findall('"colorToAsin":(.*?), "refactorEnabled":true,', str(response.text))
        try:
            try:
                parentASIN = re.findall(r', "parentAsin":"(.*?)",', str(response.text))[-1]
            excepto:
                parentASIN = re.findall(r'&parentAsin=(.*?)&', str(response.text))[-1]
        excepto:
            parentASIN = ''
        # parentASIN = parentASIN[-1] if parentASIN !=[] else ""
        print("parentASIN:",parentASIN)
        if list_ASIN_all_findall:
            list_ASIN_all_str = "".join(list_ASIN_all_findall)
            lista_ASIN_todos_dict = eval(lista_ASIN_todos_str)
            para asin_min_key, asin_min_value en list_ASIN_all_dict.items():
                if asin_valor_min:
                    asin_min_value = asin_min_value['asin']
                    news_info['parentASIN'] = parentASIN
                    news_info['secondASIN'] = asin_min_value
                    news_info['rankSecondASINUrl'] = f "https://www.amazon.com/Textile-Decorative-Striped-Corduroy-Pillowcases/dp/{asin_min_value}/ref=zg_bs_3732341_sccl_1/136-3072892-8658650?psc=1"
                    yield scrapy.Request(news_info["rankSecondASINUrl"], callback=self.parse_detail_info,meta={"news_info": deepcopy(news_info)})


    def parse_detail_info(self, response):
        """
        
        :param respuesta:
        :return:
        """
        item = response.meta['news_info']
        ASIN = item['segundoASIN']
        # print('--------------------------------------------------------------------------------------------')
        # with open('amazon_h.html', 'w') as f:
        # f.write(response.body.decode())
        # print('--------------------------------------------------------------------------------------------')
        pro_details = response.xpath('//table[@id="productDetails_detailBullets_sections1"]//tr')

        pro_detalles = {}
        for pro_row in pro_details:
            pro_detail[pro_row.xpath('./th/text()').extract_first().strip()] = pro_row.xpath('./td//text()').extract_first().strip()

        print("pro_detalle",pro_detalle)
        ships_from_list = response.xpath(
            '//div[@tabular-attribute-name="Barcos de"]/div//span//text()').extract()
        # 物流方
        prueba:
            entrega = lista_de_envíos[-1]
        excepto:
            entrega = ""
        vendedor = "".join(response.xpath('//div[@id="tabular-buybox"]//div[@class="tabular-buybox-text"][3]//text()').extract()).strip().replace("'", "")
        si vendedor == "":
            vendedor = "".join(response.xpath('//div[@class="a-section a-spacing-base"]/div[2]/a/text()').extract()).strip().replace("'", "")
        seller_link_str = "".join(response.xpath('//div[@id="tabular-buybox"]//div[@class="tabular-buybox-text"][3]//a/@href').extract())
        # if vendedor_enlace_str:
        # vendedor_enlace = "https://www.amazon.com" + seller_link_str
        # else:
        # vendedor_enlace = ''
        seller_link = "https://www.amazon.com" + seller_link_str if seller_link_str else ''

        brand_link = response.xpath('//div[@id="bylineInfo_feature_div"]/div[@class="a-section a-spacing-none"]/a/@href').extract_first()
        pic_link = response.xpath('//div[@id="main-image-container"]/ul/li[1]//img/@src').extract_first()
        title = response.xpath('//div[@id="titleSection"]/h1//text()').extract_first()
        star = response.xpath('//div[@id="averageCustomerReviews_feature_div"]/div[1]//span[@class="a-icon-alt"]//text()').extract_first().strip()
        
        probar:
            price = response.xpath('//div[@class="a-section a-spacing-none aok-align-center"]/span[2]/span[@class="a-offscreen"]//text()').extract_first()
        excepto:
            try:
                price = response.xpath('//div[@class="a-section a-spacing-none aok-align-center"]/span[1]/span[@class="a-offscreen"]//text()').extract_first()
            excepto:
                precio = ''
        size = response.xpath('//li[@class="swatchSelect"]//p[@class="a-text-left a-size-base"]//text()').extract_first()
        
        key_v = str(pro_detail.keys())
        brand = pro_detail['Marca'] if "Marca" in clave_v else ''
        if marca == ''
            brand = response.xpath('//tr[@class="a-spacing-small po-brand"]/td[2]//text()').extract_first().strip()
        elif marca == "":
            brand = response.xpath('//div[@id="bylineInfo_feature_div"]/div[@class="a-section a-spacing-none"]/a/text()').extract_first().replace("Marca: ", "").replace("Visite la", "").replace("Tienda", '').strip()

        color = pro_detail['Color'] if "Color" in key_v else ""
        if color == "":
            color = response.xpath('//tr[@class="a-spacing-small po-color"]/td[2]//text()').extract_first()
        elif color == '':
            color = response.xpath('//div[@id="variation_color_name"]/div[@class="a-row"]/span//text()').extract_first()
        
        pattern = pro_detail['Patrón'] if "Patrón" in clave_v else ""
        if patrón == ""
            pattern = response.xpath('//tr[@class="a-spacing-small po-pattern"]/td[2]//text()').extract_first().strip()
        Material #
        probar:
            material = pro_detail['Material']
        except:
            material = response.xpath('//tr[@class="a-spacing-small po-material"]/td[2]//text()').extract_first().strip()
        Forma #
        shape = pro_detail['Shape'] if "Shape" in key_v else ""
        if shape == "":
            shape = response.xpath('//tr[@class="a-spacing-small po-item_shape"]/td[2]//text()').extract_first().strip()
        # estilo
        # cinco_puntos
        cinco_puntos =response.xpath('//div[@id="feature-bullets"]/ul/li[position()>1]//text()').extract_first().replace("\"", "'")
        size_num = len(response.xpath('//div[@id="variation_size_name"]/ul/li').extract())
        color_num = len(response.xpath('//div[@id="nombre_color_variante"]//li').extract())
        # variant_num =
        # estilo
        # fabricante
       
        probar:
            Fabricante = pro_detalle['Fabricante'] if "Fabricante" in str(pro_detalle) else " "
        except:
            Fabricante = ""
        peso_artículo = pro_detail['Peso del artículo'] if "Peso" in str(pro_detail) else ''
        product_dim = pro_detail['Dimensiones del producto'] if "Dimensiones del producto" in str(pro_detail) else ''
        # material_producto
        
        try:
            product_material = pro_detail['Material']
        except:
            product_material = ''
        # tipo_tejido
       
        try:
            tipo_tejido = pro_detalle['Tipo de tejido'] if "Tipo de tejido" in str(pro_detalle) else " "
        except:
            tipo_tejido = ""

        star_list = response.xpath('//table[@id="histogramTable"]//tr[@class="a-histogram-row a-align-center"]//td[3]//a/text()').extract()
        si lista_estrella:
            try:
                star_1 = star_list[0].strip()
            except:
                estrella_1 = 0
            try:
                star_2 = star_list[1].strip()
            excepto:
                estrella_2 = 0
            try:
                star_3 = star_list[2].strip()
            excepto:
                estrella_3 = 0
            try:
                star_4 = star_list[3].strip()
            excepto:
                estrella_4 = 0
            try:
                star_5 = star_list[4].strip()
            excepto:
                estrella_5 = 0

        si no:
            star_1 = 0
            estrella_2 = 0
            estrella_3 = 0
            estrella_4 = 0
            estrella_5 = 0

        if "Fecha primera disponible" in str(pro_detalle):
            data_first_available = pro_detail['Fecha Primera Disponible']
            if data_first_available:
                data_first_available = datetime.datetime.strftime(
                    datetime.datetime.strptime(data_first_available, '%B %d, %Y'), '%Y/%m/%d')
            si no:
                data_first_available = ""
        reviews_link = f'https://www.amazon.com/MIULEE-Decorative-Pillowcase-Cushion-Bedroom/product-reviews/{ASIN}/ref=cm_cr_arp_d_viewopt_fmt?ie=UTF8&reviewerType=all_reviews&formatType=current_format&pageNumber=1'
        # reviews_num, ratings_num
        scrap_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        item['entrega']=entrega
        item['vendedor']=vendedor
        item['enlace_vendedor']=enlace_vendedor
        item['enlace_marca']= enlace_marca
        item['pic_link']=enlace_pic
        item['title']=título
        item['brand']=marca
        item['star']=estrella
        item['precio']=precio
        item['color']=color
        item['patrón']=patrón
        item['material']=material
        item['shape']=forma
        item['cinco_puntos']=cinco_puntos
        item['tamaño_num']=tamaño_num
        item['color_num']=color_num
        item['Fabricante']=Fabricante
        item['peso_artículo']=peso_artículo
        item['product_dim']=dim_producto
        item['material_producto']=material_producto
        item['tipo_tejido']=tipo_tejido
        item['star_1']=star_1
        item['star_2']=star_2
        item['star_3']=star_3
        item['star_4']=star_4
        item['star_5']=star_5
        # item['ratings_num'] = ratings_num
        # item['reviews_num'] = reviews_num
        item['tiempo_desechos']=tiempo_desechos
        item['enlace_opiniones']=enlace_opiniones
        item['tamaño']=tamaño
        item['datos_primeros_disponibles']=datos_primeros_disponibles

        producir elemento

Cuando recopile una cantidad considerable de datos, cambie la IP y gestione el reconocimiento de captchas.

4. Métodos para descargar middlewares

4.1 process_request(self, request, spider)

A. Llamada cuando cada solicitud pasa por el middleware de descarga.

B. Devolver None: Si no se devuelve ningún valor (o devolver None explícitamente), el objeto de solicitud se pasa al descargador o a otros métodos process_request de menor peso.

C. Devolución del objeto Respuesta: No se realizan más peticiones y se devuelve la respuesta al motor.

D. Devuelve el objeto Solicitud: El objeto request se pasa al planificador a través del motor. Se omiten otros métodos process_request con menor peso.

4.2 process_response(self, request, response, spider)

A. Llamada cuando el descargador completa la petición HTTP y pasa la respuesta al motor.

B. Respuesta de retorno: Pasada a la araña para su procesamiento o al método process_response de otro middleware de descarga con menor peso.

C. Devuelve el objeto Solicitud: Pasado al planificador a través del motor para posteriores peticiones. Se omiten otros métodos process_request con menor peso.

D. Configure la activación del middleware y establezca los valores de ponderación en settings.py. Los pesos más bajos tienen prioridad.

middlewares.py

4.3 Configurar IP proxy

clase ProxyMiddleware(objeto):
    def process_request(self,request, spider):
        request.meta['proxy'] = proxyServer
        request.header["Proxy-Authorization"] = proxyAuth

    def process_response(self, request, response, spider):
        if response.status != '200':
            request.dont_filter = True
            devolver solicitud  

4.4 Cambiar User-Agent o cookies.

clase AmazonspiderDownloaderMiddleware:
    # No es necesario definir todos los métodos. Si un método no está definido,
    # scrapy actúa como si el middleware downloader no modifica el
    # objetos pasados.
    @método_class
    def from_crawler(cls, crawler):
        # Este método es utilizado por Scrapy para crear sus arañas.
        s = cls()
        crawler.signals.connect(s.araña_abierta, signal=señales.araña_abierta)
        devuelve s

    def process_request(self, request, spider):
    	# USER_AGENTS_LIST: setting.py
        user_agent = random.choice(USER_AGENTS_LIST)
        request.headers['User-Agent'] = user_agent
        cookies_str = 'la cookie pegada desde el navegador'
        # transferencia de cookies_str a cookies_dict
        cookies_dict = {i[:i.find('=')]: i[i.find('=') + 1:] for i in cookies_str.split('; ')}
        request.cookies = cookies_dict
        # print("---------------------------------------------------")
        # print(request.headers)
        # print("---------------------------------------------------")
        return None

    def procesar_respuesta(self, petición, respuesta, araña):
        return respuesta

    def procesar_excepción(self, petición, excepción, araña):
        pass

    def araña_abierta(self, araña):
        spider.logger.info('Araña abierta: %s' % spider.name)

4.5 Visite Raspado Código de verificación de Amazon para desbloquear desde Amazon.

def captcha_verfiy(nombre_img):
    # captcha_verfiy
    reader = easyocr.Reader(['ch_sim', 'es'])
    # reader = easyocr.Reader(['es'], detection='DB', recognition = 'Transformer')
    
    result = reader.readtext(img_name, detail=0)[0]
    # result = reader.readtext('https://www.somewebsite.com/chinese_tra.jpg')
    si resultado:
        result = result.replace(' ', '')
    devolver resultado


def descargar_captcha(captcha_url):
    # descargar-captcha
    response = requests.get(captcha_url, stream=True)
    prueba
        with open(r'./captcha.png', 'wb') as logFile:
            for chunk in respuesta:
                logFile.write(chunk)
            logFile.close()
            print("¡Descarga realizada!")
    excepto Exception como e:
        print("¡Error en el registro de descarga!")


clase AmazonspiderVerifyMiddleware:
    
    @classmethod
    def from_crawler(cls, crawler):
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=señales.spider_opened)
        devolver s

    def process_request(self, request, spider):

        return None

    def procesar_respuesta(self, petición, respuesta, araña):
        # print(respuesta.url)
        if 'Captcha' in response.text:
            headers = {
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
            }
            session = requests.session()
            resp = session.get(url=response.url, headers=cabeceras)
            response1 = etree.HTML(resp.text)
           
            captcha_url = "".join(response1.xpath('//div[@class="a-row a-text-center"]/img/@src'))
            amzon = "".join(response1.xpath("//input[@name='amzn']/@value"))
            amz_tr = "".join(response1.xpath("//entrada[@nombre='amzn-r']/@valor"))
           
            descargar_captcha(captcha_url)
           
            captcha_text = captcha_verfiy('captcha.png')
           
            url_new = f "https://www.amazon.com/errors/validateCaptcha?amzn={amzon}&amzn-r={amz_tr}&field-keywords={captcha_text}"
            resp = session.get(url=url_new, headers=cabeceras)
            if "Lo sentimos, tenemos que asegurarnos de que no eres un robot" not in str(resp.text):
                response2 = HtmlResponse(url=url_nueva, headers=headers,body=resp.text, encoding='utf-8')
                if "Lo sentimos, tenemos que asegurarnos de que no eres un robot" not in str(response2.text):
                    return respuesta2
            else:
                return request
        si no
            return response

    def procesar_excepción(self, petición, excepción, araña):
        pass

    def araña_abierta(self, araña):
        spider.logger.info('Araña abierta: %s' % spider.name)

Eso es todo el código sobre Scraping datos de Amazon.

Si cualquier ayuda por favor deje Soporte OkeyProxy saber.

Proveedores de proxy recomendados: Okeyproxy - Top 5 Socks5 Proxy Provider con 150M+ Proxies Residenciales de 200+ Países. Prueba gratuita de 1 GB de proxies residenciales ahora!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *