Estoy intentando extraer información de un producto de una página web mediante scrapy. Mi página web que se va a eliminar se ve así:
- comienza con una página de lista de productos con 10 productos
- un clic en el botón "siguiente" carga los siguientes 10 productos (la URL no cambia entre las dos páginas)
- uso LinkExtractor para seguir el enlace de cada producto en la página del producto y obtener toda la información que necesito
Traté de replicar el siguiente botón de llamada ajax pero no puedo trabajar, así que estoy probando el selenio. Puedo ejecutar el controlador web de selenium en un script separado, pero no sé cómo integrarlo con scrapy. ¿Dónde debo poner la parte de selenio en mi araña?
Mi araña es bastante estándar, como la siguiente:
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
Se agradece cualquier idea. ¡Gracias!
Respuestas:
Realmente depende de cómo necesita raspar el sitio y cómo y qué datos desea obtener.
Aquí hay un ejemplo de cómo puede seguir la paginación en eBay usando
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()
Estos son algunos ejemplos de "arañas de selenio":
También hay una alternativa a tener que utilizar
Selenium
conScrapy
. En algunos casos, el uso deScrapyJS
middleware es suficiente para manejar las partes dinámicas de una página. Ejemplo de uso en el mundo real:fuente
self.driver.get(response.url)
?self.driver.page_source
se pasa a una instancia de Selector para que Scrapy analice el HTML, forme las instancias de elementos, las pase a las tuberías, etc. O bien, las cookies de selenio se pueden analizar y pasar a Scrapy para realizar solicitudes adicionales. Pero, si no necesita el poder de la arquitectura de marco fragmentada, entonces, claro, puede usar solo selenio, ya que es bastante poderoso para localizar los elementos.driver.page_source
y pasarlo a laSelector()
..Si (la URL no cambia entre las dos páginas), entonces debe agregar dont_filter = True con su scrapy.Request () o scrapy encontrará esta URL como un duplicado después de procesar la primera página.
Si necesita renderizar páginas con javascript, debe usar scrapy-splash , también puede verificar este middleware scrapy que puede manejar páginas de javascript usando selenium o puede hacerlo iniciando cualquier navegador sin cabeza
Pero una solución más eficaz y rápida es inspeccionar su navegador y ver qué solicitudes se realizan durante el envío de un formulario o la activación de un evento determinado. Intente simular las mismas solicitudes que envía su navegador. Si puede replicar las solicitudes correctamente, obtendrá los datos que necesita.
Aquí hay un ejemplo :
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))
Cuando la URL de paginación es la misma para todas las páginas y usa la solicitud POST, entonces puede usar scrapy.FormRequest () en lugar de scrapy.Request () , ambos son iguales pero FormRequest agrega un nuevo argumento ( formdata = ) al constructor.
Aquí hay otro ejemplo de araña de este publicación :
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
fuente