Próbuję wydobyć informacje o produkcie ze strony internetowej za pomocą scrapy. Moja strona internetowa do pobrania wygląda następująco:
- zaczyna się od strony product_list z 10 produktami
- kliknięcie przycisku „dalej” ładuje następnych 10 produktów (adres URL nie zmienia się między dwiema stronami)
- Używam LinkExtractor, aby przejść do każdego linku do strony produktu i uzyskać wszystkie potrzebne informacje
Próbowałem zreplikować wywołanie next-button-ajax-call, ale nie mogę zacząć działać, więc próbuję selenu. Mogę uruchomić webdriver selenu w osobnym skrypcie, ale nie wiem jak zintegrować się z scrapy. Gdzie mam umieścić część selenu w moim pająku drapiącym?
Mój pająk jest dość standardowy, jak poniżej:
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
Każdy pomysł jest mile widziany. Dziękuję Ci!
Odpowiedzi:
To naprawdę zależy od tego, jak chcesz zeskrobać witrynę oraz jak i jakie dane chcesz uzyskać.
Oto przykład, jak możesz śledzić paginację w serwisie eBay za pomocą
Scrapy
+Selenium
: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()
Oto kilka przykładów „pająków selenu”:
Istnieje również alternatywa dla korzystania
Selenium
zScrapy
. W niektórych przypadkach do obsługi dynamicznych części strony wystarczy użycieScrapyJS
oprogramowania pośredniego . Przykładowe użycie w świecie rzeczywistym:źródło
self.driver.get(response.url)
?self.driver.page_source
jest on przekazywany do instancji selektora, aby Scrapy przeanalizował kod HTML, uformował instancje pozycji, przekazał je do potoków itp. Lub też pliki cookie selenu mogą zostać przeanalizowane i przesłane do Scrapy w celu wykonania dodatkowych żądań. Ale jeśli nie potrzebujesz mocy architektury szkieletowej scrapy, to oczywiście możesz użyć tylko selenu - on sam jest dość potężny w lokalizowaniu elementów.driver.page_source
i przekaż go doSelector()
..Jeśli (adres URL nie zmienia się między dwiema stronami), powinieneś dodać dont_filter = True do twojego scrapy.Request () lub scrapy znajdzie ten adres jako duplikat po przetworzeniu pierwszej strony.
Jeśli chcesz renderować strony za pomocą javascript, powinieneś użyć scrapy-splash , możesz również sprawdzić to scrapy middleware, które obsługuje strony javascript przy użyciu selenu lub możesz to zrobić uruchamiając dowolną przeglądarkę bezgłową
Ale skuteczniejszym i szybszym rozwiązaniem jest zbadanie przeglądarki i sprawdzenie, jakie żądania są wysyłane podczas przesyłania formularza lub wywołania określonego zdarzenia. Spróbuj zasymulować te same żądania, które wysyła Twoja przeglądarka. Jeśli uda Ci się poprawnie powtórzyć żądanie (-a), otrzymasz potrzebne dane.
Oto przykład :
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))
Kiedy adres URL paginacji jest taki sam dla każdej strony i używa żądania POST, możesz użyć scrapy.FormRequest () zamiast scrapy.Request () , oba są takie same, ale FormRequest dodaje nowy argument ( formdata = ) do konstruktora.
Oto kolejny przykład pająka z tego postu :
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
źródło