Si en el JSON de resultado les aparecen caracteres raros como “\u0043”, coloquen la siguiente línea en su “custom_settings”:
'FEED_EXPORT_ENCODING': 'utf-8',
Introducción, definiciones y ética
Introducción y definiciones
Ética y Legalidad
Configuración del entorno de trabajo con Jupyter
HTML: Requests y BeautifulSoup
Descargando una página web
Parseando HTML con BeautifulSoup
Extrayendo información
Manejo de errores
Descargando contenido
Contenido multimedia
Unificando el scraper
Scraping JavaScript con Selenium
Instalación y configuración de Selenium
Sitios dinámicos y Selenium
Selección de elementos
Interactuando con los elementos
Scrapeando escalas y tarifas
Construyendo Funciones
Construyendo la función para unificar el scraper
Demoras dinámicas
Comentarios finales
APIs
Introducción a APIs
Utilizando APIs: Construir una URL
Utilizando APIs: Tokens y Búsqueda
Obteniendo la discografía
Obteniendo los albums
Fin del proyecto + bonus
Scrapy, Tesseract y Proxies
Scrapy
Ejecutando el scraper con scrapy
Proxies
Tesseract
Conclusión y cierre del curso
Aún no tienes acceso a esta clase
Crea una cuenta y continúa viendo este curso
Aportes 26
Preguntas 5
Si en el JSON de resultado les aparecen caracteres raros como “\u0043”, coloquen la siguiente línea en su “custom_settings”:
'FEED_EXPORT_ENCODING': 'utf-8',
EN el minuto 7 no se ve la pantalla solo al profe que va indicando
Modifique el código para que agregue la sección de cada artículo y para que funcione el click al botón next, que con la versión del profesor no me funciono.
import scrapy
from scrapy.crawler import CrawlerProcess
class Spider12(scrapy.Spider):
name = 'spider12'
allowed_domains = ['pagina12.com.ar']
custom_settings = {'FEED_FORMAT': 'json',
'FEED_URI': 'resultados_scrapy.json',
'DEPTH_LIMIT' : 2,
'FEED_EXPORT_ENCODING' : 'utf-8'}
start_urls = ['https://www.pagina12.com.ar/secciones/el-pais',
'https://www.pagina12.com.ar/secciones/economia',
'https://www.pagina12.com.ar/secciones/sociedad',
'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
'https://www.pagina12.com.ar/secciones/ciencia',
'https://www.pagina12.com.ar/secciones/el-mundo',
'https://www.pagina12.com.ar/secciones/deportes',
'https://www.pagina12.com.ar/secciones/contratapa']
def parse(self, response):
featured_el = response.xpath('//div[@class="featured-article__container"]//h2/a/@href').get()
if featured_el is not None:
yield response.follow(featured_el, callback=self.parse_new)
news = response.xpath('//div[@class="article-box__container"]/h2/a/@href').getall()
for new in news:
yield response.follow(new, callback=self.parse_new)
next_page = 'https://www.pagina12.com.ar{}'.format(response.xpath('//a[@class="pagination-btn-next"]/@href').get())
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
def parse_new(self, response):
title = response.xpath('//div[@class="article-titles"]//h1/text()').get()
body = ' '.join(response.xpath('//div[@class="article-text"]/p/text()').getall())
section = response.xpath('//div[@class="suplement"]/a/text()').get()
yield {'section' : section,
'url' : response.url,
'title' : title,
'body' : body}
if __name__ == '__main__':
process = CrawlerProcess()
process.crawl(Spider12)
process.start()
Si alguno usó Visual Studio, y le dio error al intentar usar Scrapy, verifiquen:
-Que lo tienen instalado. (pip install scrapy)
-Que tienen Microsoft Visual C++ 14.0 o superior
Código completo para usar en vscode u otro IDE:
import scrapy
from scrapy.crawler import CrawlerProcess
class Spider12(scrapy.Spider):
name = 'spider12'
allowed_domains = ['pagina12.com.ar']
custom_settings = {'FEED_FORMAT': 'json',
'FEED_URI': 'resultados.json',
'FEED_EXPORT_ENCODING': 'utf-8',
'DEPTH_LIMIT': 2}
start_urls = ['https://www.pagina12.com.ar/secciones/el-pais',
'https://www.pagina12.com.ar/secciones/economia',
'https://www.pagina12.com.ar/secciones/sociedad',
'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
'https://www.pagina12.com.ar/secciones/deportes',
'https://www.pagina12.com.ar/secciones/el-mundo',
'https://www.pagina12.com.ar/secciones/contratapa']
def parse(self, response):
# Artículo promocionado
nota_promocionada = response.xpath('//section[@class="top-content"]//h2/a/@href').get()
if nota_promocionada is not None:
yield response.follow (nota_promocionada, callback=self.parse_nota)
# notas secundarias
notas_secundarias = response.xpath('//div[@class="articles-list is-grid-col2 grid-mobile-row"]//h3/a/@href').getall()
for nota_sec in notas_secundarias:
yield response.follow(nota_sec, callback=self.parse_nota)
# Listado notas
notas = response.xpath('//div[@class="article-list"]//h4/a/@href').getall()
for nota in notas:
yield response.follow(nota, callback=self.parse_nota)
# Link a la siguiente página
next_page = response.xpath('//a[@class"next"]/@href')
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
def parse_nota(self, response):
titulo = response.xpath('//div[@class="article-titles"]/h1/text()').get()
volanta = response.xpath('//div[@class="article-titles"]/h2/text()').get()
fecha = response.xpath('//div[@class="time"]/span/@datetime').get()
copete = response.xpath('//div[@class="article-sumary"]/text()').get()
autor = response.xpath('//div[@class="article-author"]/text()').get()
cuerpo = response.xpath('//div[@class="article-text"]/p/text()').get()
yield {'url': response.url,
'titulo': titulo,
'volanta': volanta,
'fecha': fecha,
'copete': copete,
'autor': autor,
'cuerpo': cuerpo}
process = CrawlerProcess()
process.crawl(Spider12)
process.start()
Despues ejecutar en Anaconda Promt:
python scrapy_p12.py
No me trae nada el scraper ¿Alguien sabe? Me aparece esto en consola:
2020-04-26 21:35:32 [scrapy.core.engine] INFO: Spider opened
2020-04-26 21:35:32 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-04-26 21:35:32 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
Mi código es:
import scrapy
from scrapy.crawler import CrawlerProcess
class Spider12(scrapy.Spider):
name = "Spider12"
allowed_domains = ["pagina12.com.ar"]
custom_settings = {"FEED_FORMAT":"json", "FEED_URI":"resultados.json", "DEPTH_LIMIT":2, "FEED_EXPORT_ENCODING": "utf-8",}
start_urls = ['https://www.pagina12.com.ar/secciones/el-pais',
'https://www.pagina12.com.ar/secciones/economia',
'https://www.pagina12.com.ar/secciones/sociedad',
'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
'https://www.pagina12.com.ar/secciones/el-mundo',
'https://www.pagina12.com.ar/secciones/deportes',
'https://www.pagina12.com.ar/secciones/cultura',
'https://www.pagina12.com.ar/secciones/contratapa']
def parse(self, response):
# Articulo promocionado
nota_promocionada = response.xpath("//div[@class='featured-article__container']/h2/a/@href").get()
if nota_promocionada is not None:
yield response.follow(nota_promocionada, call_back=self.parse_nota)
# Lista de noticias
noticias = response.xpath("//ul[@class='article-list']//li//a/@href").getall()
for noticia in noticias:
yield response.follow(noticia, callback=self.parse_nota)
# Link a la siguiente página
next_page = response.xpath("//a[@class='pagination-btn-next']/@href")
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
def parse_nota(self, response):
titulo = response.xpath("//div[@class='article-title']/text()").get()
cuerpo = "".join(response.xpath("//div[@class='article-text']/p/text()").getall())
yield {"url":response.url, "titulo":titulo, "cuerpo":cuerpo}
process = CrawlerProcess()
process.crawl(Spider12)
process.start
Hicimos todo en jupyter notebook para que después lo abandone, diga que no funciona y aparezca ejecutándolo en otro entorno, nos cortó todo a la mitad!! Grande el profe!!
ni sirven sus ejercicios, no hay seguimiento 😦 la pagina ya cambio, en teoria solo cambiando los xpath deberia de funcionar y no, ya llevo 2 dias y no logro que funcione 😦
En el modulo de beautifulsoap y requests todo me funciono correctamente en la seccion de noticias de videojuegos de vandal.elespanol.com, pero en esta seccion tratè de hacer lo mismo con scrapy pero obtengo un error 500 - forbiden by robot.txt, explore el archivo robot.txt de vandal.net y aparece esto:
User-agent: Scrapy
Disallow: /
He intentado con un user-agent diferente y el problema persiste.
la observacion es para revisar el archivo robots.txt antes de hacer el scrapying, perdi algo de tiempo por no hacerlo. my fault.
Les comparto las funciones con los xpath actualizados para el sitio a Julio de 2021
def parse(self, response):
# Process featured article
featured_note = response.xpath('//article[@class="top-content"]//h2/a/@href').get()
if featured_note is not None:
yield response.follow(featured_note, callback=self.parse_note)
# Notes list
notes = response.xpath('//div[@class="articles-list"]//h4/a/@href').getall()
for note in notes:
yield response.follow(note, callback=self.parse_note)
# Next page
next_page = response.xpath('//a[@class="next"]/@href').get()
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
def parse_note(self, response):
title = response.xpath('//article[@class="article-full section"]//h1/text()').get()
body = response.xpath('//div[@class="article-main-content article-text "]//text()').getall()
if body is not None:
body = ' '.join(body)
yield {'url': response.url,
'title': title,
'body': body}
Pagina12 para el día 9/24/2020 ha cambiado totalmente, sus clases también se modificaron, así que dejo el código por si alguien tiene inconvenientes, ya lo testee y funciona correctamente:
Puedo juntar Scrapy con selenium? Por ejemplo hacer un parse que ejecute use selenium.
FEED_FORMAT y FEED_URI están deprecated. Aquí un ejemplo de la estructura actual:
custom_settings = {
'FEEDS':
{ "pagina12.json":
{
"format":"json",
"encoding":"utf-8",
}
},
"DEPTH_LIMIT":2
}
Aquí el código funcionando al 30/01/22, la web de pagina12 cambio mucho; por ello hice unas modificaciones.
Pd.: deberían actualizar este curso.
import scrapy
from scrapy.crawler import CrawlerProcess
class Spider12(scrapy.Spider):
name = 'spider13'
allowed_domains = ['pagina12.com.ar']
custom_settings = {'FEED_FORMAT': 'json',
'FEED_URI': 'resultados-p12.json',
'FEED_EXPORT_ENCODING': 'utf-8',
'DEPTH_LIMIT': 2}
start_urls = ['https://www.pagina12.com.ar/secciones/el-pais',
'https://www.pagina12.com.ar/secciones/economia',
'https://www.pagina12.com.ar/secciones/sociedad',
'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
'https://www.pagina12.com.ar/secciones/deportes',
'https://www.pagina12.com.ar/secciones/el-mundo',
'https://www.pagina12.com.ar/secciones/contratapa']
def parse(self, response):
# Artículo promocionado 1 columna
nota_promocionada = response.xpath('//div[@class="article-item__content"]//h2/a/@href').get()
if nota_promocionada is not None:
yield response.follow (nota_promocionada, callback=self.parse_nota)
# Artículo secundarios 2 columnas
notas_secundarias = response.xpath('//div[@class="article-item__content"]//h3/a/@href').getall()
for nota_sec in notas_secundarias:
yield response.follow(nota_sec, callback=self.parse_nota)
# Artículos de cultura y espectáculos - tiene diferente diseño a las demás secciones
notas_cultura = response.xpath('//div[@class="article-box__container"]//h2/a/@href').getall()
for nota_cul in notas_cultura:
yield response.follow(nota_cul, callback=self.parse_nota)
# Listado de artículos
notas = response.xpath('//div[@class="articles-list"]//h4/a/@href').getall()
for nota in notas:
yield response.follow(nota, callback=self.parse_nota)
# Link a la siguiente página
next_page = response.xpath('//a[@class="next"]/@href').get()
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
def parse_nota(self, response):
titulo = response.xpath('//article[@class="article-full section"]//h1/text()').get()
apartado = response.xpath('//h5[@class="current-tag"]/a/text()').get()
volanta = response.xpath('//article[@class="article-full section"]//h4/text()').get()
fecha = response.xpath('//article[@class="article-full section"]//time/text()').get()
cuerpo = response.xpath('//article[@class="article-full section"]//p/text()').get()
yield {'url': response.url,
'titulo': titulo,
'apartado': apartado,
'volanta': volanta,
'fecha': fecha,
'cuerpo': cuerpo}
process = CrawlerProcess()
process.crawl(Spider12)
process.start()
Qué poderosa la herramienta de scrapy para poder seguir páginas y no cambiar el DOM. Estaría genial que se pudiera emplear para páginas dinámicas y no lidiar tanto con el StaleElementReferenceException de selenium
Para obtener los xpath mas facil al elemento le da copiar y va a salir una lista selecciona el que dice copiar xpath.
Pues me fue muy util ver esta clase junto a la documentacion que esta en la pagina de scrapy, para saber que tengo que actualizar, ademas de eso yo corry mi codigo directamente con el comando
scrapy runspider .\scrapoccidente.py
desde el el shell donde esta corriendo el entorno virtual, y pues comparando mi codigo con el de la clase me quedo mas corto y con algunas diferencias marcadas como el que no tengo que poner callback = self.parse sino que solo pongo self.parse. Ademas que me fue muy util el curso de xpath de el profe Facundo Garcia para poder crear estos, teniendo en cuenta que lo realice con otra web de noticias de mi ciudad.
y aqui esta el codigo:
import scrapy
class occSpider(scrapy.Spider):
name = 'occSpider'
allowed_domains = ["occidente.co"]
custom_settings = { "FEED_FORMAT": "json",
"FEED_URI": "occidente.json",
"FEED_EXPORT_ENCODING": "utf-8",
"DEPTH_LIMIT": 10}
start_urls = ["https://occidente.co/politica/"]
def parse(self, response):
news = response.xpath('//*//a[@class="text-black text-decoration-none"]/@href').getall()
for n in news:
yield response.follow(n, self.parse_news)
for next_page in response.xpath('//*//div[@class="nav-links text-center mx-auto"]/div/a[contains(.,"Siguiente")]/@href'):
yield response.follow(next_page, self.parse)
def parse_news(self, response):
title = response.xpath('//div[@class="container"]//h1[@class="main-post-title art-title font-family-judson font-size-48 font-weight-bold line-height-1em"]/text()').getall()
body = response.xpath('*//div[@class="font-family-roboto font-size-18"]/p/text()').getall()
yield {"url": response.url,
"title": title,
"body": body}
for next_page in response.xpath('//nav/ul[@class="pager"]/li[@class="next"]/a/@href'):
yield response.follow(next_page, self.parse)
uhmm, en el minuto 7, cuando empieza hacer el proceso nuevamente, no se ve lo que hace, solo aparece el hablando 😦
El siguiente paso de este curso es seguir con el curso de scrapy
Alguien me podria ayudar?
Me tira el siguiente error
File “<ipython-input-37-c309d42b79fb>”, line 31
yield {‘url’: response.url,
^
SyntaxError: invalid syntax
class Spider12(scrapy.Spider):
name = 'spider12'
allowed_domains = ["pagina12.com.ar"]
customs_settings = {"FEED FORMAT": "json",
"FEED_URI": "resultados.json",
"DEPTH_LIMIT": 2}
start_urls = ['https://www.pagina12.com.ar/secciones/el-pais',
'https://www.pagina12.com.ar/secciones/economia',
'https://www.pagina12.com.ar/secciones/sociedad',
'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
'https://www.pagina12.com.ar/secciones/el-mundo',
'https://www.pagina12.com.ar/secciones/deportes',
'https://www.pagina12.com.ar/secciones/psicologia',
'https://www.pagina12.com.ar/secciones/contratapa']
def parse(self, response):
nota_promocionada = xpath('//div[@class="featured-article__container"]/h2/a/@href').get()
if nota_promocionada is not None:
yield response.follow(nota_promocionada, callback=self.parse_nota)
notas = response.xpath('//ul[@class="article-list"]//li//a/@href').getall()
for nota in notas:
yield response.follow(notas, callback=self.parse_nota)
#Pasar a la siguiente pagina
next_page = response.xpath('//a[@class="pagination-btn-next"]/@href)')
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
def parse_nota(self, response):
titulo = responde.xpath('//div[@class="article-title"]/text()').get()
cuerpo = ''.join(responde.xpath('//div[@class="article-text"]/p/text()').getall
yield {'url': response.url,
'titulo': titulo,
'cuerpo': cuerpo}
me sale este error "ReactorNotRestartable " y no trae nada
Compañeros, me corrio en la consola de Spyder que viene con Anaconda, por alguna razón no me corrio con los demás.
a alguien le ha funcionado con otra pagina que no sea pagina12?
Alguien que hubiera podido ejecutar el código del Profesor sin errores??
Hice este scraper para el diario la republica pero no jala y me devuelve un archivo vacío. Alguien quien me pueda orientar?
import requests as rq
import lxml.html as html
import scrapy
from scrapy.crawler import CrawlerProcess
base_url='https://www.larepublica.co'
class spiderLR(scrapy.Spider): #hereda las funciones de araña
name="spiderLR" #asi se llama
allowed_domains= [base_url] #no se puede salir del dominio
custom_settings={'FEED_FORMAT':"csv", #formato de salida de datos
'FEED_URI': "resultados.csv"} #nombre de archivo
start_urls=['https://www.larepublica.co/finanzas',
'https://www.larepublica.co/economia',
'https://www.larepublica.co/empresas',
'https://www.larepublica.co/ocio',
'https://www.larepublica.co/globoeconomia',
'https://www.agronegocios.co/',
'https://www.larepublica.co/analisis',
'https://www.larepublica.co/asuntos-legales',
'https://www.larepublica.co/caja-fuerte']
def parse_home(self, response):
linknotas=response.xpath('//h2[@class="headline"]/a/@href').getall()
for link in linknotas:
yield response.follow(link, callback=self.parse_nota)
next_page=response.xpath('//button[@class="button moreCont"]')
if next_page is not None:
yield response.follow(next_page, callback=#funcionque procesará lo que parezca en siguiente)
def parse_nota(self, response):
titulo=response.xpath('//div[@class="medium-9 medium-push-3 columns text-fill-section"]//a/text()').get()
cuerpo="".join(response.xpath('//div[@class="articleWrapper "]/p/text()').getall())
yield {"url":response.url,
"titulo":titulo,
"cuerpo":cuerpo}
if __name__=="__main__":
process=CrawlerProcess()
process.crawl(spiderLR)
process.start()
```
scrapy !!
¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.