Ich versuche, Produktinformationen mithilfe von Scrapy von einer Webseite zu entfernen. Meine zu kratzende Webseite sieht folgendermaßen aus:
- Beginnt mit einer product_list-Seite mit 10 Produkten
- Ein Klick auf "Weiter" lädt die nächsten 10 Produkte (URL ändert sich nicht zwischen den beiden Seiten)
- Ich benutze LinkExtractor, um jedem Produktlink auf der Produktseite zu folgen und alle Informationen zu erhalten, die ich brauche
Ich habe versucht, den Next-Button-Ajax-Aufruf zu replizieren, kann aber nicht funktionieren, also versuche ich es mit Selen. Ich kann den Web-Treiber von Selen in einem separaten Skript ausführen, weiß aber nicht, wie ich ihn in Scrapy integrieren soll. Wo soll ich den Selenteil in meine kratzende Spinne stecken?
Meine Spinne ist ziemlich normal, wie die folgende:
class ProductSpider(CrawlSpider):
name = "product_spider"
allowed_domains = ['example.com']
start_urls = ['http://example.com/shanghai']
rules = [
Rule(SgmlLinkExtractor(restrict_xpaths='//div[@id="productList"]//dl[@class="t2"]//dt'), callback='parse_product'),
]
def parse_product(self, response):
self.log("parsing product %s" %response.url, level=INFO)
hxs = HtmlXPathSelector(response)
# actual data follows
Jede Idee wird geschätzt. Vielen Dank!
Antworten:
Es hängt wirklich davon ab, wie Sie die Site kratzen müssen und wie und welche Daten Sie erhalten möchten.
Hier ist ein Beispiel, wie Sie die Paginierung bei ebay mit
Scrapy
+ verfolgen könnenSelenium
:import scrapy from selenium import webdriver class ProductSpider(scrapy.Spider): name = "product_spider" allowed_domains = ['ebay.com'] start_urls = ['http://www.ebay.com/sch/i.html?_odkw=books&_osacat=0&_trksid=p2045573.m570.l1313.TR0.TRC0.Xpython&_nkw=python&_sacat=0&_from=R40'] def __init__(self): self.driver = webdriver.Firefox() def parse(self, response): self.driver.get(response.url) while True: next = self.driver.find_element_by_xpath('//td[@class="pagn-next"]/a') try: next.click() # get the data and write it to scrapy items except: break self.driver.close()
Hier einige Beispiele für "Selenspinnen":
Es gibt auch eine Alternative zur Verwendung
Selenium
mitScrapy
. In einigen Fällen reicht die Verwendung vonScrapyJS
Middleware aus, um die dynamischen Teile einer Seite zu verarbeiten. Beispiel für eine reale Verwendung:quelle
self.driver.get(response.url)
?self.driver.page_source
an eine Selector-Instanz übergeben, damit Scrapy den HTML-Code analysiert, die Elementinstanzen bildet, sie an Pipelines weitergibt usw. Oder Selen-Cookies können analysiert und an Scrapy übergeben werden, um zusätzliche Anforderungen zu stellen. Wenn Sie jedoch nicht die Leistung der Scrapy-Framework-Architektur benötigen, können Sie natürlich nur Selen verwenden - es ist selbst sehr leistungsfähig, um die Elemente zu lokalisieren.driver.page_source
und geben Sie es an dieSelector()
..Wenn (URL ändert sich nicht zwischen den beiden Seiten), sollten Sie dont_filter = True mit Ihrem Scrapy hinzufügen. Request () oder Scrapy finden diese URL nach der Verarbeitung der ersten Seite als Duplikat.
Wenn Sie Seiten mit Javascript rendern müssen, sollten Sie Scrapy-Splash verwenden . Sie können auch diese Scrapy-Middleware überprüfen, die Javascript-Seiten mit Selen verarbeiten kann, oder Sie können dies tun, indem Sie einen beliebigen Headless-Browser starten
Eine effektivere und schnellere Lösung besteht jedoch darin, Ihren Browser zu überprüfen und festzustellen, welche Anforderungen beim Senden eines Formulars oder beim Auslösen eines bestimmten Ereignisses gestellt werden. Versuchen Sie, dieselben Anforderungen zu simulieren, die Ihr Browser sendet. Wenn Sie die Anforderung (en) korrekt replizieren können, erhalten Sie die benötigten Daten.
Hier ist ein Beispiel :
class ScrollScraper(Spider): name = "scrollingscraper" quote_url = "http://quotes.toscrape.com/api/quotes?page=" start_urls = [quote_url + "1"] def parse(self, response): quote_item = QuoteItem() print response.body data = json.loads(response.body) for item in data.get('quotes', []): quote_item["author"] = item.get('author', {}).get('name') quote_item['quote'] = item.get('text') quote_item['tags'] = item.get('tags') yield quote_item if data['has_next']: next_page = data['page'] + 1 yield Request(self.quote_url + str(next_page))
Wenn die Paginierungs-URL für alle Seiten gleich ist und die POST-Anforderung verwendet, können Sie Scrapy.FormRequest () anstelle von Scrapy.Request () verwenden . Beide sind identisch, aber FormRequest fügt dem Konstruktor ein neues Argument ( formdata = ) hinzu.
Hier ist ein weiteres Spinnenbeispiel aus diesem Beitrag :
class SpiderClass(scrapy.Spider): # spider name and all name = 'ajax' page_incr = 1 start_urls = ['http://www.pcguia.pt/category/reviews/#paginated=1'] pagination_url = 'http://www.pcguia.pt/wp-content/themes/flavor/functions/ajax.php' def parse(self, response): sel = Selector(response) if self.page_incr > 1: json_data = json.loads(response.body) sel = Selector(text=json_data.get('content', '')) # your code here # pagination code starts here if sel.xpath('//div[@class="panel-wrapper"]'): self.page_incr += 1 formdata = { 'sorter': 'recent', 'location': 'main loop', 'loop': 'main loop', 'action': 'sort', 'view': 'grid', 'columns': '3', 'paginated': str(self.page_incr), 'currentquery[category_name]': 'reviews' } yield FormRequest(url=self.pagination_url, formdata=formdata, callback=self.parse) else: return
quelle