#python #pandas #dataframe #scrapy
#python #pandas #фрейм данных #scrapy
Вопрос:
Я использую Scrapy для очистки некоторых данных веб-сайта. Но я не могу сделать шаг, чтобы правильно получить свои данные.
Это результат моего кода (см. Код ниже):
В командной строке:
scrapy crawl myspider -o items.csv
Вывод:
asin_product product_name
ProductA,,,ProductB,,,ProductC,,, BrandA,,,BrandB,,,BrandC,,,
ProductA,,,ProductD,,,ProductE,,, BrandA,,,BrandB,,,BrandA,,,
#Note that the rows are representing the start_urls and that the ',,,'
#three commas are separating the data.
Желаемый результат:
scrapy crawl myspider -o items.csv
Start_URL asin_product product_name
URL1 ProductA BrandA
URL1 ProductB BrandB
URL1 ProductC BrandC
URL2 ProductA BrandA
URL2 ProductD BrandB
URL2 ProductE BrandA
Мой используемый код в Scrapy:
import scrapy
from amazon.items import AmazonItem
class AmazonProductSpider(scrapy.Spider):
name = "AmazonDeals"
allowed_domains = ["amazon.com"]
#Use working product URL below
start_urls = [
"https://www.amazon.com/s?k=shoesamp;ref=nb_sb_noss_2", # This should
be #URL 1
"https://www.amazon.com/s?k=computeramp;ref=nb_sb_noss_2" # This should
be #URL 2
]
def parse(self, response):
items = AmazonItem()
title = response.xpath('//*[@class="a-size-base-plus a-color-base a-
text-normal"]/text()').extract()
asin = response.xpath('//*[@class ="a-link-normal"]/@href').extract()
# Note that I devided the products with ',,,' to make it easy to separate
# them. I am aware that this is not the best approach.
items['product_name'] = ',,,'.join(title).strip()
items['asin_product'] = ',,,'.join(asin).strip()
yield items
Ответ №1:
Прежде всего, рекомендуется использовать css при запросе по классу.
Теперь к вашему коду:
Название продукта находится в теге a (URL продукта). Таким образом, вы можете выполнять итерации по ссылкам и сохранять URL-адрес и заголовок.
<a class="a-link-normal a-text-normal" href="/adidas-Mens-Lite-Racer-Running/dp/B071P19D3X/ref=sr_1_3?keywords=shoesamp;amp;qid=1554132536amp;amp;s=gatewayamp;amp;sr=8-3">
<span class="a-size-base-plus a-color-base a-text-normal">Adidas masculina Lite Racer byd tênis de corrida</span>
</a>
Вам нужно создать по одному AmazonItem
объекту на строку в вашем CSV-файле.
def parse(self, response):
# You need to improve this css selector because there are links which
# are not a product, this is why I am checking if title is None and continuing.
for product in response.css('a.a-link-normal.a-text-normal'):
# product is a selector
title = product.css('span.a-size-base-plus.a-color-base.a-text-normal::text').get()
if not title:
continue
# The selector is already the a tag, so we only need to extract it's href attribute value.
asin = product.xpath('./@href').get()
item = AmazonItem()
item['product_name'] = title.strip()
item['asin_product'] = asin.strip()
yield item
Комментарии:
1. Спасибо @Luiz! Это работает, но два небольших замечания: 1). Возможно ли увидеть URL-адреса? Точно так же, как в примере, дополнительный столбец с URL-адресом? 2). Я думаю, вы забыли ‘ в этой строке: asin = product.xpath(‘./@href).get() # по крайней мере, я добавил запятую после href. 3). При выполнении значения сохраняются в файле CSV, но не уверен, почему .. но после каждой строки появляется пустая строка. Это из-за «если не продолжить заголовок»? Большое спасибо!!
2. @Roverflow 1) Вы можете получить URL, который сгенерировал ответ, используя response.url. Итак, вы можете сделать item[‘url’] = response.url. 2) Да, я забыл ‘. 3) Я должен быть связан с continue, откройте csv в виде текстового файла и посмотрите, как в файле присутствуют запятые, возможно, это связано с вашим средством просмотра CSV (Excel, open(libre)office).
Ответ №2:
- Сделайте start_url доступным в методе parse
вместо использования start_urls вы можете передавать свои первоначальные запросы из метода с именем start_requests (см.https://docs.scrapy.org/en/latest/intro/tutorial.html ?выделите=start_requests#наш-первый-паук).
С каждым запросом вы можете передавать начальный URL-адрес в качестве метаданных. Затем эти метаданные будут доступны в вашем методе синтаксического анализа (см.https://docs.scrapy.org/en/latest/topics/request-response.html ?выделите=meta#scrapy.http.Request.meta).
def start_requests(self):
urls = [...] # this is equal to your start_urls
for start_url in urls:
yield Request(url=url, meta={"start_url": start_url})
def parse(self, response):
start_url = response.meta["start_url"]
- выдайте несколько элементов, по одному для каждого продукта
Вместо объединения названий и брендов вы можете получить несколько элементов из parse. Для примера ниже я предполагаю, что заголовки списков и asin имеют одинаковую длину.
for title, asin in zip(title, asin):
item = AmazonItem()
item['product_name'] = title
item['asin_product'] = asin
yield item
PS: вы должны проверить amazons robots.txt . Они могут не позволить вам очистить их сайт и запретить ваш IP (https://www.amazon.de/robots.txt)
Комментарии:
1. Спасибо за вашу помощь, Рафаэль! Но это решение не хранит данные «должным образом», как в примере выше, верно?
2. Я обновил свой ответ дополнительным шагом для выходного формата @Roverflow