No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Extrayendo informaci贸n

6/30
Recursos

Aportes 190

Preguntas 18

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

隆Reto resuelto! 馃槃

def notices(soup):
    """Funci贸n que recibe un objeto soup de una categor铆a determinada, 	 
    y devuelve los links de todas las noticias pertenecientes a ella"""

    featured_article = soup.find('div', attrs={
        'class': 'featured-article__container'
    })
    featured_article_link = [featured_article.find('a').get('href')]
    
    articles_h2 = soup.find('ul', attrs={
        'class': 'article-list'
    }).find_all('h2')
    articles_a = [article_h2.find('a', attrs= {
        'class': ''
    }) for article_h2 in articles_h2]
    
    articles_links = [article_a.get('href') for article_a in articles_a]
    
    return featured_article_link + articles_links

# Ejemplo de uso

university_section = BeautifulSoup(
    requests.get('https://www.pagina12.com.ar/secciones/universidad-diario').text,
    'lxml'
)

notices(university_section)

# Out
"""
['https://www.pagina12.com.ar/234308-con-record-de-inscriptos-en-la-unaj',
 'https://www.pagina12.com.ar/234323-agenda',
 'https://www.pagina12.com.ar/234350-el-costo-oculto-de-ir-a-estudiar',
 'https://www.pagina12.com.ar/233660-clonacion-bebes-de-diseno-etica-y-tecnologia',
 'https://www.pagina12.com.ar/233666-los-veinte-anos-de-agd',
 'https://www.pagina12.com.ar/233684-cada-vez-mas-personas-estudian-para-ser-docentes',
 'https://www.pagina12.com.ar/233038-el-aporte-de-las-universidades-al-plan-contra-el-hambre',
 'https://www.pagina12.com.ar/232346-la-conferencia-de-joanne-rosenthal-sangre-y-experiencia-posd',
 'https://www.pagina12.com.ar/232351-reflexiones-sobre-la-gratuidad-universitaria',
 'https://www.pagina12.com.ar/232362-a-70-anos-de-la-gratuidad-el-fin-de-la-universidad-elitista',
 'https://www.pagina12.com.ar/232394-festival-en-la-unaj',
 'https://www.pagina12.com.ar/232304-agenda',
 'https://www.pagina12.com.ar/232296-congreso-de-psicologia-el-sintoma-y-la-epoca',
 'https://www.pagina12.com.ar/231748-el-nuevo-local-de-la-lua',
 'https://www.pagina12.com.ar/231764-agenda']
"""

comparto mi codigo con una funci貌n extra del curso de ingenieria de datos con python donde revisamos que la estructura de la url sea correcta, de la pagina en la cual me base, algunas url no estaban completas, les faltaba el host.

import requests
from bs4 import BeautifulSoup
import re

url = 'https://vandal.elespanol.com/noticias/videojuegos'

# estructura correcta de las url
is_well_formed_link = re.compile(r'^https?://.+/.+$')
is_root_path = re.compile(r'^/.+$')

#se hace el requerimiento a la pagina
vandal = requests.get(url)

#se hace el parse en formato lxml
s = BeautifulSoup(vandal.text, 'lxml')

#encontramos las secciones en el html en div con class:pildora
secciones = s.find_all('div', attrs={'class':'pildora'})

# con un list comprehension tomamos la etiqueta href
links_secciones = [seccion.a.get('href') for seccion in secciones]

# con la funcion build_link validamos que la estructura del link sea correcta

def build_link(url, link):
    if is_well_formed_link.match(link):
        return link
    elif is_root_path.match(link):
        return '{}{}'.format(url, link)
    else:
        return '{}/{}'.format(url, link)

links_secciones_modificadas = []

#validamos la estructura de cada link y la a帽adimos a link_secciones_modificadas
for link in links_secciones:
    links_secciones_modificadas.append(build_link(url, link))```

Reto hecho hoy Junio 19, 2021 (la estructura de la p谩gina ha cambiado un poco):

## Funci贸n que recibe una variable de BeautifulSoap
# y entrega un listado con los links de las noticias
# p.e. s_seccion  que contiene la secci贸n el-pa铆s
def get_links_section (url, x):
    links_section = []
    
    # Primera noticia promocional
    #new_1 = x.find('div', attrs={'class':'article-item__content'}).a.get('href')
    new_1 = x.find('h2', attrs={'class': 'title-list'}).a.get('href')
    links_section.append(url + new_1)
    
    # Segunda y tercera noticia promocional
    new_2_3 = x.find('div', attrs={'class': 'articles-list is-grid-col2 grid-mobile-row'}).find_all('h3')
    
    links_section = links_section + [url + link.a.get('href') for link in new_2_3]
    
    # Listado de noticias
    news_list = x.find_all('div', attrs={'class': 'article-item__content-footer-wrapper gutter-small deco-bar-here-left'})
    links_section = links_section + [url + link.a.get('href') for link in news_list]
    
    return links_section

Un pequeno a[porte para quienes estan haciendo el curso al igual que yo en Octubre 2021, los ultimos 鈥榟ref鈥 del ejercicio traen la url cortada (no trae el dominio web ni el https, me imagino que es un tema de evitar el scrapping), entonces para tener un href completo hice lo siguiente, que espero les sirva de ejemplo:

hiper = article.a.get('href')
link_nuevo = 'https://www.pagina12.com.ar'+hiper
link_nuevo

Es muy importante que vayan revisando el tipo de sus variables o resultados con type para que no obtengan resultados inesperados tratanto de aplicar m茅todos a objetos que no corresponden.

Y cada vez que regreso a repasar el curso, la estructura de la p谩gina que se ve en los videos ya cambio.
Por tanto, debes tomar esto en cuenta al tomar este curso pues puede no ser igual a lo que muestra el profesor. Esto no te impide seguir con el curso, s贸lo ad谩ptate al cambio.

Hoy, 22 de septiembre del 2020, la estructura es tal, que el reto se puede resolver con 茅ste c贸digo y tomando en cuenta que las noticias est谩n divididas como en tres tipos o secciones diferentes.
Espero les sirva

def fnt_obtener_links(s):
    top_article = s.find('div', attrs={'class': 'article-item__content'})
    top_article_link = top_article.a.get('href')
    
    lista_h3 = s.find_all('h3', attrs={'class': 'title-list'})
    lista_links_seccion1 = [link.a.get('href') for link in lista_h3]
    
    lista_h4 = s.find_all('h4', attrs={'class': 'title-list'})
    lista_links_seccion2 = [link.a.get('href') for link in lista_h4]
    
    lista_links = [top_article_link] + lista_links_seccion1 + lista_links_seccion2
    
    return lista_links

import requests
from bs4 import BeautifulSoup

# resultado_request = requests.get('https://www.pagina12.com.ar/secciones/el-pais')
resultado_request = requests.get('https://www.pagina12.com.ar/secciones/economia')

s = BeautifulSoup(resultado_request.text, 'lxml') 

fnt_obtener_links(s)

Resultado:

['https://www.pagina12.com.ar/293956-una-lista-de-los-que-se-quedan-a-invertir',
 'https://www.pagina12.com.ar/293943-tarifas-abusivas-en-buenos-aires',
 'https://www.pagina12.com.ar/293939-nos-recomponemos-de-un-industricidio',
 'https://www.pagina12.com.ar/293935-paritarias-a-fuego-lento',
 'https://www.pagina12.com.ar/293931-jubilados-septiembre-2020-quienes-cobran-este-miercoles-23',
 'https://www.pagina12.com.ar/293930-asignacion-universal-por-embarazo-septiembre-2020-quienes-co',
 'https://www.pagina12.com.ar/288274-asignacion-universal-por-embarazo-septiembre-2020-la-anses-f',
 'https://www.pagina12.com.ar/288267-jubilados-septiembre-2020-la-anses-fijo-las-fechas-de-cobro',
 'https://www.pagina12.com.ar/293894-el-pbi-cayo-el-19-1-en-segundo-trimestre-del-ano',
 'https://www.pagina12.com.ar/293879-martin-guzman-expone-el-proyecto-de-presupuesto-2021-ante-lo',
 'https://www.pagina12.com.ar/293853-como-son-los-nuevos-creditos-para-electrodomesticos-que-lanz']

Hola, dejo mi funci贸n para obtener los links del articulo promocionado y los demas art铆culos en una lista:

<code>
def getArticles(section_page):
    # Get featured article link
    featured_article = section_page.find('div', attrs={'class': 'featured-article-sections'})
    featured_art_link = featured_article.a.get('href')
    
    # Get articles links in the list
    articles = section_page.find('ul', attrs={'class': 'article-list'}).find_all('li')
    article_links = [article.a.get('href') for article in articles if article.a] # Only takes valid <a> tags
    
    # Insert featured article link into the list
    article_links.insert(0, featured_art_link)
    
    return article_links

Despu茅s de ver el video 3 veces por fin pude traer los links 馃槂

Realice el reto haciendo Scraping a la pagina de Xataka en la seccion analisis:

Codigo:

Output desde Anaconda Prompt:

Reto - 17-Oct-2020

import requests
from bs4 import BeautifulSoup

url = 'https://www.pagina12.com.ar/secciones/economia'

def getlinks(soup):
    news = soup.find_all('div', attrs = {'class':'article-item__content'})

    links_news = [new.a.get('href') for new in news]
    print(links_news)

def main():
    p12 = requests.get(url)
    soup  = BeautifulSoup(p12.text, 'lxml')
    getlinks(soup)

if __name__ == '__main__':
    main()

Por si alguien cierra el proyecto y al abrirlo no le funcionan los comandos, ha de saber que debe volver a correr todas las l铆neas del proyecto de nuevo.

Febrero 2022
Hola, si est谩n haciendo el curso en estas fechas pueden haber notado que el formato de la p谩gina web de P谩gina 12 cambio su estructuraci贸n. Para acomodarme a la nueva infraestructura dise帽茅 la siguiente funci贸n que cumple el reto propuesto por el profesor, espero que sea de utilidad.

def get_sections_links(some_soup):
    base_url = 'https://www.pagina12.com.ar'
    section_links = []
    for i in range(2,5):
        hn = f'h{i}'
        nodes = some_soup.find_all(hn, attrs={'class':'title-list'})
        for node in nodes:
            temp_link = node.find('a').get('href')
            section_links.append(base_url + temp_link)
    return section_links

隆Hola comunidad de Platzi ! , aqu铆 mi soluci贸n al reto, hoy es 14-07-2022 y la estructura de la p谩gina ha cambiado un poco, esta vez hay dos art铆culos promocionados. Espero que les sirva y si tienen una mejor forma de hacerlo les pido por favor que lo dejen en los comentarios 馃槃

def get_articles_links( s_input, url ):
    featured_articles = s_input.find_all('article', attrs={'class':'article-item--featured'})
    links = []
    for article in featured_articles:
        links.append(url + article.find('h3').find('a').get('href'))
    
    normal_articles = s_input.find_all('article', attrs={'class': 'article-item article-item--teaser'})
    for narticle in normal_articles:
        links.append(url + narticle.find('h4').find('a').get('href'))
    
    
    return links

Dejo mi aporte del reto actualizado a Mayo del 2023

links_reto = []
url = 'https://www.pagina12.com.ar/'
url_2 = 'https://www.pagina12.com.ar'

#Campo url:       link de la pagina principal
#Campo texto_url: link de alguna secci贸n de la pagina web

def link_header(url,texto_url):

  #------------------------------------------------------------------------------------------------------------------

  #realizamos la solicitud para extraer la informaci贸n del articulo principal de alguna secci贸n de la pagina

  url_header = requests.get(texto_url)
  
  #Realizamos la codificaci贸n con BS4 para poder manipular la informaci贸n con el parser 'lxml'

  parseo_reto = BeautifulSoup(url_header.text, 'lxml')

  ###############################################

  #LINK HEADER

  ###############################################


  #Buscamos el link articulo principal, en este caso se encuentra en la secci贸n h2 con clase 'h1 title-list'

  link_tittle = parseo_reto.find('h2',attrs ={'class':'h1 title-list'}).find('a').get('href')

  #Le adicionamos un texto para que quede bien el link y lo apilamos en una lista vacia que definimos mas arriba 

  link_tittle_2 = url_2 + link_tittle

  links_reto.append(link_tittle_2)

  ###############################################

  #LINKS SEGUNDA SECCI脫N

  ###############################################

  segundo_links = parseo_reto.find('div', {'articles-list is-grid-col2 grid-mobile-row'}).find_all('h3')

  segundo_links_2 = [url_2 + links.find('a').get('href') for links in segundo_links]

  links_reto.append(segundo_links_2)

  ###############################################

  #LINKS LISTA TERCERA SECCI脫N

  ###############################################


  try:

    [links_reto.append(url_2 + links.find('a').get('href')) for links in tercero_links]


  except AttributeError:
    pass
  

  return links_reto


Soluci贸n al reto Abril de 2023

import requests
from bs4 import BeautifulSoup

url = 'https://www.pagina12.com.ar'

response = requests.get(url)
home = BeautifulSoup(response.text, 'lxml')
#obtenemos la secci贸n Ul que contiene los links
links_parsed = home.find('ul', attrs = {'class':'horizontal-list main-sections hide-on-dropdown'}).find_all('li')

#obtenemos los links mediante List Comprehension
links = [link.a.get('href') for link in links_parsed]


#definimos la funcion del reto
#al d铆a de hoy el periodico tiene sus noticias en tres containers
#se hayan todas y se almacenan en variables para luego hayar los enlaces

def get_links_seccion(seccion): 
        main_article = seccion.find('h2',attrs = {'class':'h1 title-list'})
        featured_articles = seccion.find_all('h3', attrs = {'class': 'h2 title-list featured-article'})
        inline_articles = seccion.find_all('h4', attrs = {'class': 'h2 is-display-inline title-list'})
        link_main = [url + main_article.a.get('href')]
        links_featured = [url + link.a.get('href') for link in featured_articles]
        links_inline= [url + link.a.get('href') for link in inline_articles]
        
        return(link_main + links_featured+ links_inline)

# ejemplo de uso:
seccion2 = links[2]
print(seccion2)
response2 = requests.get(seccion2)
seccion2_parse= BeautifulSoup(response2.text, 'lxml')
print(get_links_seccion(seccion2_parse))

#resultado: 

['https://www.pagina12.com.ar/541403-organizaciones-feministas-y-de-dd-hh-repudiaron-el-0800-vida', 'https://www.pagina12.com.ar/541380-robots-realizan-un-trasplante-pulmonar-casi-sin-intervencion', 'https://www.pagina12.com.ar/541369-bronca', 'https://www.pagina12.com.ar/541338-juicio-a-sebastian-villa-no-podia-hablar-con-mi-madre-por-lo', 'https://www.pagina12.com.ar/541331-la-impresionante-tromba-marina-que-sorprendio-a-los-vecinos-', 'https://www.pagina12.com.ar/541317-un-ex-gran-hermano-fue-apunalado-cuando-intentaba-agredir-a-', 'https://www.pagina12.com.ar/512622-llega-un-nuevo-eclipse-hibrido-que-es-y-cuando-podra-verse', 'https://www.pagina12.com.ar/541256-por-que-elon-musk-suspendio-el-lanzamiento-del-cohete-starsh', 'https://www.pagina12.com.ar/541245-italia-hallan-dos-toneladas-de-cocaina-flotando-cerca-de-la-', 'https://www.pagina12.com.ar/541235-scapolan-esta-tarde-el-jury-dara-su-veredicto-sobre-las-acus', 'https://www.pagina12.com.ar/541205-sebatian-villa-primera-audiencia-en-el-juicio-por-lesiones-y']
<def articles_links(seccion):

    """Get the page content"""
    pais = requests.get(seccion)

    """Convert into a BS """
    pais_ = BeautifulSoup(pais.text)

    """Extract general URL"""
    base = pais_.find('div',{'class':'logo-content'}).a.get('href')

    """Extract the articles  """

    a =pais_.find(
    'section', attrs = {
    'class': 'list-content'
    }
    ).find_all('div', attrs= {'class':'article-item__header'}
        )
    
    """get the links"""
    Links = [ seccionaa.get('href') for seccionaa in [ seccionaa.find('a') for seccionaa in a]]

    """Convert  links"""
    links_ = [base + link for link in Links]


    return links_
     > 

Si estan viendo esto en 2021 y ven que la pagina rep煤blica cambio lo pueden hacer as铆:

Aqu铆 est谩 mi soluci贸n, lo hice para la secci贸n de cultura:

import requests
from bs4 import BeautifulSoup
url = 'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos/21-06-2020'
culture = requests.get(url)


if __name__ == "__main__":
    soup = BeautifulSoup(culture.text, 'html.parser')
    featured_article_container = soup.find('ul', attrs={'class' : 'cover-articles'})
    featured_article_title = featured_article_container('h2')[0].text
    
    featured_article_url = featured_article_container('a')[0]['href']
    other_articles = soup.select('ul.article-list.article-list--other')
    articles = other_articles[0].find_all('li')
    print('--- * '  *10 )
    for article in articles:
        title = article.find('h2').text
        article_url = article.find('a')['href']
        print(f'New article {title}')
        print(f'Article at {article_url}')

    
    print(f'Featured article title: {featured_article_title}')
    print(f'Featured article url: {featured_article_url}')
    print('--- * '  *10 )

si les sale un error de NoneType como a mi que estube trayendo la secci贸n de hoy en la ual esta no tenia href lo que se puede hacer es :
links_secciones = [seccion.a.get(鈥榟ref鈥) for seccion in secciones if seccion.a is not None]

Esa pagina a hoy (25 de enero de 2022) ya ha cambiado mucho y toca revisar muy bien que es lo que se hace para seguir el ritmo de la clase鈥s hasta bueno porque se practica como que el doble.
LA parte mas dura va siendo sacar los links de cada noticia.

Vamos avanzando y conociendo algunas funciones y la manera de extraer cierta informaci贸n, no obstante, a煤n no comprendo del todo el objetivo final de hacer esto. El ejemplo de extraer todas las noticias de un diario a qu茅 me conducir铆a? una vez tengo toda la lista de noticias de qu茅 sirve? Me parece que construir un ejemplo m谩s pr谩ctico con un objetivo m谩s claro desde el inicio, ayudar铆a mucho a la l贸gica del curso.

Hola, comparto mi funci贸n del reto.

En mi caso todas las noticias estaban en un tag 鈥榓rticle鈥, dentro de este tag est谩 otro 鈥榓鈥 que tiene el atributo 鈥榟ref鈥 con el link, adem谩s los links no conten铆an el host por lo que doy un formato final, en mi caso hice el primer m茅todo get con el host terminado en 鈥/鈥 y es por eso que agrego un if.

Estoy feliz. hace un a帽o no pod铆a comprender esto y ahora creo que me desenvuelvo mejor, ojal谩 a alguien le sirva, no dejen de aprender 馃槃

def get_links_from_pagina12_seccion(bs4_object_page, host):
    # Obtiene todos los tag 'article'
    articles_list = bs4_object_page.find_all('article')
    # Obtiene todos los links contenidos en los tag 'a', dentro del atributo 'href'
    articles_link_list = [article.a.get('href') for article in articles_list]
    # Formatea 'host'
    if host[-1] == '/':
        host = host[:len(host) - 1]
    # Formatea lista de links
    articles_link_list = [link_article if link_article.startswith(host) else host + link_article for link_article in articles_link_list]
    return articles_link_list

Pruebas

articles_link_list_1 = get_links_from_pagina12_seccion(featured_article, p12.request.url)
articles_link_list_1

Resultados

[鈥https://www.pagina12.com.ar/413385-de-almuerzos-con-empresarios-a-una-gira-por-estados-unidos鈥,
https://www.pagina12.com.ar/413377-escandalo-en-el-parlasur-malestar-en-la-ucr-con-el-operador-鈥,
https://www.pagina12.com.ar/413373-el-testimonio-de-una-tia-en-el-juicio-de-las-brigadas-que-bu鈥,
https://www.pagina12.com.ar/413370-organizaciones-sociales-y-sindicales-protestaron-por-la-suba鈥,
https://www.pagina12.com.ar/413350-contrapunto-entre-zabaleta-y-rodriguez-larreta-por-las-organ鈥,
https://www.pagina12.com.ar/413338-la-destruccion-judicial-del-estado-de-derecho鈥,
https://www.pagina12.com.ar/413317-diputados-trabaja-en-la-ley-de-alquileres鈥,
https://www.pagina12.com.ar/413304-alberto-fernandez-y-gabriel-boric-recorrieron-el-museo-sitio鈥,
https://www.pagina12.com.ar/413287-estados-unidos-saco-a-la-argentina-del-listado-de-paises-con鈥,
https://www.pagina12.com.ar/413270-la-interna-de-juntos-por-el-cambio-los-radicales-inician-el-鈥,
https://www.pagina12.com.ar/413267-el-discurso-de-campana-de-rodriguez-larreta-contra-los-pique鈥橾

Comparto mi c贸digo al 25/04/022, le agregue la funci贸n del curso de David para determinar si el link esta bien formado, y una funci贸n para limpiar el titulo.
Me guie de este aporte de Daniel S谩nchez para obtener todos los links: https://platzi.com/comentario/3575413/

import requests
from bs4 import BeautifulSoup
import lxml
import re

url = "https://www.pagina12.com.ar"

response = requests.get(url)

soup = BeautifulSoup(response.text, 'lxml')

# Every section is inside a il that is inside a ul
sections = soup.find('ul', attrs={'class':'horizontal-list main-sections hide-on-dropdown'}).find_all('li')

sections_links = [section.a.get('href') for section in sections_li]
#print(sections_links)

sections_titles = [section.a.text for section in sections_li]
#print(sections_titles)

def build_link(url, link):
    is_well_formed_link = re.compile(r'^https?://.+/.+$')
    is_root_path = re.compile(r'^/.+$')
    
    if is_well_formed_link.match(link):
        return link
    elif is_root_path.match(link):
        return '{}{}'.format(url, link)
    else:
        return '{}/{}'.format(url, link)

def clean_text(text):
    return text.replace("\xa0", "")


def get_response(url):
    return requests.get(url)


def get_soup(response):
    # Soup object
    soup = BeautifulSoup(response.text, 'lxml')
    
    return soup
def get_featured_article(soup):
    
    # Get the featured article of the section 
    # by searching the FIRST div with class = article-item__content
    featured_article = soup.find('div', attrs={'class':'article-item__content'})
    
    featured_article_link = None
    featured_article_title = None
    
    if featured_article:
        featured_article_link = build_link(url,featured_article.a.get('href'))
        featured_article_title = clean_text(featured_article.a.text)
    
    # Returns a tuple
    return (featured_article_link, featured_article_title)
def get_all_articles(soup):

    article_groups = soup.find_all('div', attrs={'class':'articles-list'})
    
    # List of the articles left
    articles_list_links = []
    articles_list_titles = []
    
    for group in article_groups:
        # All the article of the group
        articles = group.find_all('article', attrs={'class':'article-item'})
        # Loop for every article
        for article in articles:
            # The div that has the article inside
            div_of_article = article.find('div', attrs={'class':'article-item__content-footer-wrapper'})
            articles_list_links.append(build_link(url, div_of_article.a.get('href')))
            articles_list_titles.append(clean_text(div_of_article.a.text))
    
    # Returns a tuple
    return (articles_list_links, articles_list_titles)
for section in sections_links:
    # Get the response
    section_response = get_response(section)
    # Only execute if the response status code was ok
    if section_response.status_code == 200:
        section_soup = get_soup(section_response)
        featured_article_link, featured_article_title = get_featured_article(section_soup)
        articles_list_links, articles_list_titles = get_all_articles(section_soup)
        print("\n- Section: ", section)
        print("- Response: ", section_response.status_code)
        print("- Featured article link: ", featured_article_link)
        print("- Featured article title: ", featured_article_title)
        print("- Articles list links: ", articles_list_links)
        print("- Articles list titles: ", articles_list_titles)
    else:
        print(f"Error: {section_response.status_code}")

Estoy haci茅ndolo en 2022, y la p谩gina de El Pa铆s cambi贸 un poco, ahora los art铆culos est谩n almacenados en etiquetas _article _ dentro de un div. As铆 lo resolv铆:

# Define una nueva funcion
def obtener_articulos(soup):
    # Crea un array para almacenar los enlaces
    lista_articulos = []
    
    # Busca el div que almacena el primer articulo
    articulo_principal = soup.find('div', attrs={'class':'article-item__content'})
    if articulo_principal:
        # Agrega el href del a que esta dentro del h2 
        lista_articulos.append(articulo_principal.h2.a.get('href'))
    
    # Busca todos los divs que almacenan articulos
    grupo_articulos = soup.find_all('div', attrs={'class':'articles-list'})
    # Hay dos grupos de articulos, dos semi featured, y el resto de los articulos
    # Esta iteracion hace un loop por los grupos de articulos
    for grupo in grupo_articulos:
        articulos = grupo.find_all('article', attrs={'class':'article-item'})
        
        # Y esta hace un loop entre los articulos dentro de ese grupo de articulos
        for articulo in articulos:
            # Busca el div que almacena el texto, aunque el href tambien se podria conseguir en la img
            contenedor = articulo.find('div', attrs={'class':'article-item__content-footer-wrapper'})
            # Asigna el enlace al array
            lista_articulos.append(contenedor.a.get('href'))
            
    return lista_articulos

Si obtienes el error:

AttributeError: 'NoneType' object has no attribute 'get'

se soluciona con:

links_secciones = [seccion.a.get('href') for seccion in secciones if seccion.a is not None]

Propongo esta forma seg煤n la secci贸n el-pa铆s de pagina 12, en el listado inferior de noticias. He encontrado en las opciones tag.name y tag.get una ayuda grande.

[python]
from bs4 import BeautifulSoup
import requests

def obtener_notas(url):
    p12 = requests.get(url)
    s   = BeautifulSoup(p12.text, "lxml") # Text to xml

    articles_set = s.find(lambda tag:tag.name=="div" and tag.get("class")==["articles-list"] )
    print(articles_set.prettify())

    article_set = articles_set.find_all(lambda tag2:tag2.name=="div" and tag2.get("class")==["article-item__content"] )
    title_set   = [document.a.get_text() for document in article_set]
    return title_set

url = "enlace Pagina12 seccion el pais"

[/python]

Trae los t铆tulos delas noticias de una secci贸n a base de sus links

import requests
from bs4 import BeautifulSoup

url = 'https://www.pagina12.com.ar/secciones/economia'
url_page = 'https://www.pagina12.com.ar'

def getlinks(soup):
    news = soup.find_all('div', attrs = {'class':'article-item__content'})
    links_news = [url_page + new.a.get('href') for new in news]
    return(links_news)


def gettitles(links_news):
    titles = []
    for l in links_news:
        p12_titles = requests.get(l)
        soup  = BeautifulSoup(p12_titles.text, 'lxml')
        title = soup.find('div', attrs = {'class':'col 2-col'}).find('h1').get_text()
        titles.append(title)
    return(titles)
 
def main():
    p12 = requests.get(url)
    soup  = BeautifulSoup(p12.text, 'lxml')
    #getlinks(soup)
    print(gettitles(getlinks(soup)))
    


if __name__ == '__main__':
    main()

Reto realizado el 27/11/2021. Para esta fecha ya ha cambiado la estructura de la p谩gina, ahora se cuentan con tres secciones de donde se deben de extraer los links, por lo que el c贸digo me quedo de la siguiente manera:

faltante = 'https://www.pagina12.com.ar'
featured_article = s_seccion.find('div', attrs={'class':'article-item__content-footer-wrapper gutter-small deco-bar-here-left is-mobile-top'})
links_promocional = faltante + featured_article.a.get('href')

articles_grid = s_seccion.find('div', attrs={'class':'articles-list is-grid-col2 grid-mobile-row'}).find_all('h3')
article_g = articles_grid[0]
links_articles_grid = [faltante + article_g.a.get('href') for article_g in articles_grid]

articles_list = s_seccion.find('div', attrs={'class':'article-item__content-footer-wrapper gutter-small deco-bar-here-left'}).find_all('h4',attrs={'class':'is-display-inline title-list'})
article_l = articles_list[0]
links_articles_list = [faltante + article_l.a.get('href') for article_l in articles_list]

links_total = [links_promocional, links_articles_grid, links_articles_list]

print(links_total)

# Output:
# ['https://www.pagina12.com.ar/385504-capacitacion-por-malvinas',
#  ['https://www.pagina12.com.ar/385497-crimen-y-prejuicio',
#   'https://www.pagina12.com.ar/385502-alberto-fernandez-suma-a-la-cgt-al-peronismo-territorial'],
#  ['https://www.pagina12.com.ar/385498-juntos-por-el-cambio-entre-las-fisuras-internas-y-el-coquete',
#   'https://www.pagina12.com.ar/385496-causa-hotesur-las-razones-del-sobreseimiento-a-cristina-kirc',
#   'https://www.pagina12.com.ar/385495-imputaron-con-prision-preventiva-a-los-acusados-del-asesinat',
#   'https://www.pagina12.com.ar/385493-organizaciones-politicas-y-sociales-marcharon-a-plaza-de-may',
#   'https://www.pagina12.com.ar/385490-espionaje-a-familiares-del-ara-san-juan-el-juez-debe-definir',
#   'https://www.pagina12.com.ar/385483-cristina-fernandez-de-kirchner-se-reunio-con-las-senadoras-d',
#   'https://www.pagina12.com.ar/385451-cristina-kirchner-y-sus-hijos-fueron-sobreseidos-en-el-caso-',
#   'https://www.pagina12.com.ar/385430-secuestros-y-torturas-durante-la-dictadura-el-comodoro-retir']]

Tuve suerte de que todos los links desde h2 hasta h3 est谩n en un div con la misma clase. Agregu茅 la url antes de cada link por que son relativos y no eran usables

def _get_article_links(soup):
    section_divs = s_section.find_all('div', {'class': 'article-item__content'})
    links = [ url + link.a.get('href') for link in section_divs]
    return links

Julio 2021, esta es la funci贸n que utilic茅 para obtener los links de las noticias.

def get_links(url):
  response = requests.get(url)
  soup = BeautifulSoup(response.text, 'lxml')
  sections = soup.find('ul', class_='horizontal-list main-sections hide-on-dropdown').find_all('li')
  links_seccions = [section.a.get('href') for section in sections]

  news_links = []

  for link in links_seccions:
    sec = requests.get(link)
    sec_s = BeautifulSoup(sec.text, 'lxml')
    if 'cultura-y-espectaculos' in link:
      divs_news = sec_s.find_all('div', class_='article-box__container')
      a_links = [link.a.get('href') for link in divs_news]
      news_links.append(a_links)
    else:
      divs_news = sec_s.find_all('div', class_='article-item__content')
      a_links = [link.a.get('href') for link in divs_news]
      news_links.append(a_links)

  return news_links
def link_noticias_seccion(sopa):
    article_list = sopa.find_all('div', attrs={'class':'article-item__content'})
    noticias_seccion = ['https://www.pagina12.com.ar'+item.find('a').get('href') for item in article_list]
    return noticias_seccion
    

link_noticias_seccion(s)

['https://www.pagina12.com.ar/355936-murio-juan-carlos-del-bello',
 'https://www.pagina12.com.ar/352208-en-la-facultad-de-ciencias-sociales-se-impuso-la-lista-que-p',
 'https://www.pagina12.com.ar/352002-como-sera-la-nueva-normalidad-en-las-universidades',
 'https://www.pagina12.com.ar/351404-elecciones-en-la-uba-votan-los-profesores-de-ciencias-social',
 'https://www.pagina12.com.ar/351250-el-cbc-de-la-uba-tendra-una-sede-en-el-barrio-31',
 'https://www.pagina12.com.ar/351151-la-facultad-de-derecho-de-la-uba-habilita-la-presencialidad-',
 'https://www.pagina12.com.ar/350463-la-expansion-del-sistema-universitario-mas-estudiantes-mas-p',
 'https://www.pagina12.com.ar/346979-la-escuela-de-ciencias-informaticas-ofrece-cursos-virtuales-',
 'https://www.pagina12.com.ar/346987-cursos-abiertos-para-la-comunidad',
 'https://www.pagina12.com.ar/346733-un-futuro-de-aulas-hibridas-para-las-universidades',
 'https://www.pagina12.com.ar/345913-un-centro-universitario-de-la-innovacion-en-el-corazon-del-c']

Tal vez cambi贸 la estructura, porque veo que solucionan el reto con un filtro 鈥榟2鈥. A d铆a de hoy (22 de Diciembre de 2020), la primera noticia se puede capturar con filtro h2. M谩s espec铆ficamente, el Xpath a su link es

//div[@class="article-item__content"]/h2/a/@href

luego aparecen dos noticias m谩s con tama帽o h3 (misma estructura, pero cambia h2 por h3 en su Xpath); y una lista de noticias con tama帽o h4.

Hice el ejercicio con la secci贸n economy, y extraje su link aprovechando la variable links_secciones que definimos hace unas clases, aunque obviamente pueden extraer el link de forma manual tambi茅n. Dejo un resumen de todo hasta ac谩:

url = 'https://www.pagina12.com.ar/'
p12 = requests.get(url)
s = BeautifulSoup(p12.text, 'lxml')
secciones = s.find('ul', attrs = {'class':'horizontal-list main-sections hide-on-dropdown'})('a')
links_secciones = [s.get('href') for s in secciones]
economy = BeautifulSoup(requests.get(links_secciones[1]).text, 'lxml')

Notar que para elegir cualquier otra secci贸n, donde puse economy = BeautifulSoup(requests.get(links_secciones[1]).text, 鈥榣xml鈥), pueden reemplazar ese 1 por cualquier otro n煤mero entre 0 y len(links_secciones) - 1.

Y, finalmente, la funci贸n que cree para obtener los links es la siguiente:

def links_to_news(bs_obj):
    """Recibe un objeto BeautifulSoup (bs_obj) de una p谩gina y una secci贸n espec铆ficas, 
    y retorna una lista con todos los links a las notas/noticias (news) de esa secci贸n"""
# Primero filtramos el div con class='article-item__content'    
featured_articles = bs_obj.find_all('div', attrs={'class':'article-item__content'})
# Y despu茅s obtenemos los links para los casos h2, h3 y h4 mencionados anteriormente.
    h2_links = [f.h2.a.get('href') for f in featured_articles if f.h2]
    h3_links = [f.h3.a.get('href') for f in featured_articles if f.h3]
    h4_links = [f.h4.a.get('href') for f in featured_articles if f.h4]
    return h2_links + h3_links + h4_links

Pongo la actualizaci贸n al 26 de Diciembre 2020 sobre el link para obtener el resto de las notas.

notas = soup.find_all('h4',attrs={'class':'title-list'})
link_notas = [nota.a.get('href') for nota in notas]

P.D. Me ayud茅 de otros aportes que se hab铆an perdido en los comentarios m谩s viejos.

def getArticleLinks(url):
    page = requests.get(url)
    soup = BeautifulSoup(page.text, 'lxml')
    featured_link = soup.find('div', attrs={'class', 'featured-article__image-container'}).a.get('href')
    articles = soup.find('ul', attrs={'class':'article-list'}).find_all('div', attrs={'class': 'article-box__container'})
    articles_links = [article.h2.a.get('href') for article in articles]
    articles_links.insert(0, featured_link)
    return articles_links

Aca mi solucion.
No recibe un objeto de bs4, pero con ella pude hacerle scraping a todas las secciones, lo cual me parecio mas util. 馃殌

def get_links(seccion):
    sec = requests.get(seccion)
    s_sec = BeautifulSoup(sec.text,'lxml')
    featured_article = s_sec('div',attrs={'class':'featured-article__container'})[0].a.get('href')
    articles_list_raw = s_sec.find('ul',attrs={'class':'article-list'})
    articles_list = [articles_list_raw('a')[i].get('href') for i in range(len(articles_list_raw('a')))]
    articles_list.insert(0,featured_article)
    return articles_list

Hola. Comparto mi c贸digo en donde se le da la opci贸n al usuario que seleccione de cual categor铆a quiere los links

import requests
import bs4 

def get_section(url):
    response = requests.get(url)
    response.encoding = 'utf-8'
    soup = bs4.BeautifulSoup(response.text, 'html.parser')

    sections = list(set(soup.select('ul.horizontal-list a')))
    print('Choose a section to scraper')
    for i, section in enumerate(sections):
        print(f'Section: {i}. {section.text}')
    
    user = int(input('Option: '))

    try:
        option = sections[user]['href']
    except IndexError:
        print('Invalid Option')
    
    link_generator(option)

def link_generator(option):
    response = requests.get(option)
    response.encoding = 'utf-8'
    soup = bs4.BeautifulSoup(response.text, 'html.parser')

    news = set(soup.select('.title-list a'))

    for item in news:
        print(f"Link: {item['href']}")
    

if __name__ == '__main__':
    print('-----Welcome to your link generator-----')
    url = 'https://www.pagina12.com.ar'
    get_section(url)```

Les dejo mi soluci贸n. Estoy abierto a cualquier sugerencia. Gracias =)

# Librerias a utilizar
import requests
from bs4 import BeautifulSoup

def saludar():
    """
    saludar es una funci贸n que devuelve un breve saludo
    """
    print('----- Bienvenido a P谩gina 12 -----\n')


def elegir_seccion(url):
    """
    elegir_seccion es una funci贸n que toma la URL de P谩gina 12 y devuelve
    el n煤mero de secci贸n escogida y una lista de los links de las secciones 
    """
    # Solicitud a la URL
    pagina = requests.get(url)

    # Crear un objeto BeautifulSoup para analizar el contenido HTML
    soup = BeautifulSoup(pagina.text, 'lxml')

    # Buscar el elemento <ul>. Encontrar elementos <li>
    grupo_secciones = soup.find('ul', attrs={'class':'horizontal-list main-sections hide-on-dropdown'}).find_all('li')

    # Obtener nombres de las secciones y link de cada una de ellas
    secciones = [link.a.get_text() for link in grupo_secciones]
    links_secciones = [link.a.get('href') for link in grupo_secciones]

    # Mensaje para el usuario 
    print('Secciones de P谩gina 12: ')

    # Listar cada secci贸n con su n煤mero de orden respectivo
    # [print(f'{num+1}: {secciones[num]} -> {links_secciones[num]}') for num in range(0,len(secciones))]
    for num in range(0, len(secciones)):
        print(f'{num + 1}: {secciones[num]} -> {links_secciones[num]}')

    # Ingresar n煤mero e imprimir secci贸n elegida
    while True:
        numero = input('\n----- 驴Qu茅 secci贸n deseas elegir? ')
        try:
            numero = int(numero)
            if 1 <= numero <= len(secciones):
                break
            else:
                print('----- N煤mero fuera del rango permitido. Int茅ntelo de nuevo.')

        except ValueError:
            print('----- Entrada no v谩lida')

    print(f'----- Usted eligi贸 la secci贸n: {secciones[numero-1]}\n')

    # Retornar n煤mero de secci贸n escogida y URLs de cada secci贸n
    return numero, links_secciones


def obtener_links_articulos(num, links_secciones, url):
    """
    obtener_links_articulos es una funci贸n que toma el n煤mero de secci贸n 
    escogida, los links de las secciones y la URL de P谩gina 12
    """
    
    # Solicitud a la URL de la secci贸n
    pag_seccion = requests.get(links_secciones[num-1])

    # Crear un objeto BeautifulSoup para analizar el contenido HTML
    soup_seccion = BeautifulSoup(pag_seccion.text, 'lxml')

    # Buscar todos elementos <div> con la clase 'article-item__content'
    grupo_articulos = soup_seccion.find_all('div', attrs={'class':'article-item__content'})

    # Obtener las URLs y t铆tulos de los art铆culos (find_all devuelve una lista)
    url_articulos = [url + str(link.find('a').get('href')) for link in grupo_articulos]
    texto_articulos = [link.find('a').get_text() for link in grupo_articulos]

    # Retornar los links de los articulos y su titulo correspondiente
    return url_articulos, texto_articulos


def articulos_pagina12(url):
    """
    articulos_pagina12 toma como entrada la URL de P谩gina 12 y devuelve la
    secci贸n de inter茅s del usuario con sus articulos y sus respectivos enlaces 
    """
    # Saludar
    saludar()

    # Elegir seccion
    numero, links_secciones = elegir_seccion(url)

    # Listar los links de los articulos segun la seccion escogida
    url_articulos, texto_articulos = obtener_links_articulos(numero, links_secciones, url)

    # Imprimir cada articulo con su respectivo link
    [print(f'    > Noticia N掳{num+1}: {texto_articulos[num]} -> {url_articulos[num]}') for num in range(len(url_articulos))]


url = 'https://www.pagina12.com.ar/'
articulos_pagina12(url)

Este es mi codigo no se si este correcto

15/08/23 sonar茅 muy tonto, pero despu茅s de un par de horas sin entender y buscando la respuesta, y a punto de tirar la toalla, decid铆 hacerlo por mi cuenta y obtuve la lista de las notas:
veo que la p谩gina ha cambiado mucho.
si alguien tiene una correcci贸n o comentario, bienvenido.

<code> 
def obtener_notas(soup):
    lista_notas= []
    #obtengo el art铆culo promocionado
    featured_article=soup.find('div' , attrs={'class':'article-item__content'})
    if featured_article:
        lista_notas.append(featured_article.a.get('href'))
    #obtengo el listado de articulos
    article_list= soup.find('section', attrs= {'class':'list-content' })
    for article in article_list.find_all('article'):
        if article.a:
            lista_notas.append(article.a.get('href'))
    return lista_notas

resultado:
鈥/578674-ultraderecha-argentina-nuestro-pais-tambien-herido鈥,
鈥/578767-paso-2023-ganaron-el-fondo-milei-y-el-poder-judicial-pero-so鈥,
鈥/578960-las-claves-del-voto-milei-como-por-que-lo-que-viene鈥,
鈥/578827-de-el-dipy-a-luis-brandoni-y-marcela-pagano-como-le-fue-a-lo鈥,
鈥/578875-por-que-las-encuestas-no-previeron-el-voto-por-javier-milei-鈥,
鈥/578882-bullrich-el-dia-despues-bajo-la-sombra-de-javier-milei鈥,
鈥/578684-nueva-derecha-nuevos-desafios鈥,
鈥/578903-el-gobierno-notifico-el-tramite-iniciado-por-ana-maria-figue鈥,
鈥/578914-union-por-la-patria-redefine-la-estrategia-para-remontar-la-鈥,
鈥/578918-el-fiasco-de-la-boleta-electronica-en-caba-llego-a-la-justic鈥,
鈥/578921-el-juez-marcelo-martinez-de-giorgi-avanza-con-la-investigaci鈥,
鈥/578715-el-escrutinio-definitivo-de-las-paso-comienza-manana-por-la-鈥橾

Al 07/08/2023 la p谩gina ha sufrido varias modificaciones, por lo que les dejo mi c贸digo con la forma que encontr茅 para resolverlo

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

def scrape_noticias_pagina12():
    url = "https://www.pagina12.com.ar/secciones/el-pais"

    # Realizar la solicitud HTTP GET a la p谩gina web
    response = requests.get(url)

    # Comprobar que la solicitud se haya realizado correctamente
    if response.status_code != 200:
        print("Error al obtener la p谩gina:", response.status_code)
        return []

    # Analizar el contenido HTML con BeautifulSoup
    soup = BeautifulSoup(response.content, "html.parser")

    # Encontrar todos los elementos <h4> con la clase "title is-display-inline ff-20px-w700-ls-07"
    noticias = soup.find_all("h4", class_="title is-display-inline ff-20px-w700-ls-07")

    # Lista para almacenar los enlaces completos de las noticias
    enlaces_noticias = []

    # Obtener los enlaces completos y agregarlos a la lista
    for noticia in noticias:
        enlace = noticia.find("a").get("href")
        enlace_completo = urljoin(url, enlace)
        enlaces_noticias.append(enlace_completo)

    return enlaces_noticias

# Ejecutar la funci贸n y obtener los enlaces
enlaces_noticias_pagina12 = scrape_noticias_pagina12()

# Imprimir los enlaces completos de las noticias
for enlace in enlaces_noticias_pagina12:
    print(enlace)

20/Julio/2023

Mi funci贸n del reto

 def linksPage(soup, url):
	# cargar los links de la secci贸n de la pagina
        featured_article = soup.find('div', attrs={'class':'article-item__content'}).find('h2', attrs={'class':'title ff-31px-w800-ls-1'})
        article_list1 = soup.find('section', attrs={'class':'list-content'}).find_all('h3', attrs={'class':'title ff-31px-w800-ls-1'})
        article_list2 = soup.find('section', attrs={'class':'list-content'}).find_all('h4', attrs={'title is-display-inline ff-22px-w800-ls-07'})
        
	
	# Inicializar los vectores que contienen los links
        links1 = article_list1[0]
        links2 = article_list2[0]

	
        # Extraer el href que contiene los links de cada articulo
        feature_link = featured_article.a.get('href')
        article_links1 = [links1.a.get('href') for links1 in article_list1]
        article_links2 = [links2.a.get('href') for links2 in article_list2]
        
	# expandir el primer vector para que se iguale a las dimensiones de los otros 
        feature_link = np.expand_dims(feature_link, 0)
                
	# concatenar todo en un solo vector
        matriz_links = np.concatenate([feature_link, article_links1, article_links2])
        
	# Inicializar la matriz de vectores
        total_links=[]
        
	# a帽adir la url base + el link href de cada articulo
        for link in matriz_links:
            total_links.append(url + link)
        
        return total_links


linksPage(s_seccion, links_secciones[0])

21 de Junio 2023, la gran mayoria de clases han cambiado, es dificil obtener un output con las instrucciones del curso. Pero el contenido es bueno.

Reto completado

<

def main(url):
    espe = requests.get(url)
    so = BeautifulSoup(espe.text, "lxml")
    cabeza = so.find('ul', attrs={"class": "article-list cover-articles"}).find_all('h2')
    atn = so.find('ul', attrs={"class": "article-list article-list--other"}).find_all('h2')
    new = atn+cabeza
    print(new)

    links = ["https://www.pagina12.com.ar/"  + new.a.get("href") for new in atn]
    return links

if __name__ == '__main__':
    url = "https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos/19-05-2023"
    links = main(url)
    for i in links:
        print(i)
> 

Reto resuelto teniendo en cuenta la nueva estructura que tiene la pagina a esta fecha

def get_links():
    # URL de la p谩gina de la que se quieren extraer los links
    url = 'https://www.pagina12.com.ar/secciones/economia'

    # Hacer la petici贸n GET a la p谩gina
    response = requests.get(url)

    # Verificar que la petici贸n fue exitosa (c贸digo 200)
    if response.status_code == 200:
        # Obtener el contenido HTML de la p谩gina
        html = response.content

        # Crear un objeto BeautifulSoup (bs) a partir del contenido HTML
        soup = bs(html, 'html.parser')

        # Encontrar todos los elementos 'a' que est茅n dentro de una etiqueta 'h2' 
        # con la clase 'article-title'
        links = soup.find_all('h2', class_='h1 title-list') + soup.find_all('h3', class_='h2 title-list featured-article') + soup.find_all('h4', class_='h2 is-display-inline title-list')
            

        # Iterar sobre la lista de links encontrados para obtener su href
        for link in links:
            # Obtener el href del link
            href = link.find('a')['href']

            # Imprimir el href del link
            print(href)
    else:
        # Si la petici贸n no fue exitosa, imprimir el c贸digo de estado recibido
        print(f'Status code error: {response.status_code}')

espero les sirva

def links_seccion(elemento):
    link = elemento.get("href")
    req = requests.get(link)
    print(f"status code = {req.status_code}")
    sopa = BeautifulSoup(req.text)
    extrae=sopa.find_all("article")
    extrae = [elemento.find("a") for elemento in extrae]
    extrae = [elemento.get("href") for elemento in extrae]
    return extrae 

Para los que est谩n haciendo el curso actualmente, la estructura de la p谩gina cambi贸 un poco desde el inicio del curso, ahora hay un titular importante, dos t铆tulos secundarios y luego una lista de 8 t铆tulos menores.
El ejercicio propuesto en esta clase me qued贸 d ela siguiente manera, solo que modifique un poco la consigna, en vez de hacer una funcion que recibe un objeto bs4, cre茅 una funci贸n donde directamente se recibe el link de alguna seccion de pagina 12 (en este caso la secci贸n mundo), y dentro de la funci贸n se crea el objeto bs4 y es donde sucede la magia:

def getNewsLinks(page):

    """ Here we get the page content """
    linkPage=requests.get(page)

    """ We convert the the page content into a BS4 type variable """
    soupPage=BeautifulSoup(linkPage.text,'lxml')

    """ en uuna variable almacenamos el contenedor de los articulos """
    articles_container=soupPage.find('div',attrs={'class':'main-content'})

    """ dentro de article_list almacenamos una lista de todos los articulos dentro del contenedor"""
    article_list=articles_container.find_all('article',attrs={'class':'article-item'})

    """ obtenemos los links a los cuales redirige cada item en la lista """
    anclas_articulos=[articulos.a.get('href')for articulos in article_list]

    """ Agregamos el link originario de la p谩gina, para armar un link funcional, ya que los href que nos brinda el sitio son, por ejemplo '/deportes' , sin la parte inicial, que podemos obtener agragandolo manualmente el link de la pagina a cada ancla en la lista """
    links_anclas=[p12.request.url + ancla for ancla in anclas_articulos]


    """ devolvemos el resultados con los links de esa secci贸n del diario """
    return links_anclas

Mi soluci贸n en 2023

def content(section):
    # creation of lists to append results
    cont_name=[]
    cont_links=[]

    #first content extraction, heading and link. featured article
    cont_fet=section.find('h2',attrs={'class':'h1 title-list'})
    link_fet="https://www.pagina12.com.ar"+cont_fet.find('a').get('href')
    head_fet=cont_fet.find('a').get_text()
    cont_name.append(head_fet)
    cont_links.append(link_fet)

    #second content extraction, heading and link. secondaries featured articles
    cont_fet_2=section.find('div',attrs={'class':"articles-list is-grid-col2 grid-mobile-row"}).find_all('h3')
    links_fet_2=["https://www.pagina12.com.ar"+ link.a.get('href') for link in cont_fet_2]
    head_fet_2=[link.a.get_text() for link in cont_fet_2]

    cont_name.extend(head_fet_2)
    cont_links.extend(links_fet_2)

    # articles content extraction, heading and link. all others articles.
    cont=section.find('div',attrs={'class':"article-item__content-footer-wrapper gutter-small deco-bar-here-left"}).find_all('h4')
    links=["https://www.pagina12.com.ar"+ link.a.get('href') for link in cont]
    head=[link.a.get_text() for link in cont]

    cont_name.extend(head)
    cont_links.extend(links)



    print(cont_name)
    print(cont_links)

[鈥楤andera de largada para un extenso a帽o electoral鈥, 鈥楳esa pol铆tica: Bandera de largada para discutir la estrategia electoral鈥, 鈥楯untos por el Cambio ajusta el gui贸n en C贸rdoba鈥, 鈥楢erol铆neas desmiente a Macri鈥, 鈥楲esa humanidad: Pedidos de condena para polic铆as retirados de R铆o Negro鈥, 鈥楶or ahora nada detiene el juicio pol铆tico a los supremos鈥, 鈥楿n Plan de Gobierno hace falta鈥, 鈥楲os faltantes tienen un sesgo geogr谩fico\xa0鈥, 鈥楲a fuerte pol茅mica que abri贸 el censo 2022 sobre el distrito de La Matanza鈥, 鈥楢lberto Fern谩ndez confirm贸 la convocatoria a una mesa pol铆tica del Frente de Todos鈥, 鈥榁uelos de la muerte: c贸mo se gest贸 la repatriaci贸n del avi贸n que es s铆mbolo de los cr铆menes de la ESMA鈥橾

[鈥https://www.pagina12.com.ar/521420-bandera-de-largada-para-un-extenso-ano-electoral鈥, 鈥https://www.pagina12.com.ar/521414-mesa-politica-bandera-de-largada-para-discutir-la-estrategia鈥, 鈥https://www.pagina12.com.ar/521412-juntos-por-el-cambio-ajusta-el-guion-en-cordoba鈥, 鈥https://www.pagina12.com.ar/521430-aerolineas-desmiente-a-macri鈥, 鈥https://www.pagina12.com.ar/521405-lesa-humanidad-pedidos-de-condena-para-policias-retirados-de鈥, 鈥https://www.pagina12.com.ar/521410-por-ahora-nada-detiene-el-juicio-politico-a-los-supremos鈥, 鈥https://www.pagina12.com.ar/521411-un-plan-de-gobierno-hace-falta鈥, 鈥https://www.pagina12.com.ar/521413-los-faltantes-tienen-un-sesgo-geografico鈥, 鈥https://www.pagina12.com.ar/521323-la-fuerte-polemica-que-abrio-el-censo-2022-sobre-el-distrito鈥, 鈥https://www.pagina12.com.ar/521303-alberto-fernandez-confirmo-la-convocatoria-a-una-mesa-politi鈥, 鈥https://www.pagina12.com.ar/521239-vuelos-de-la-muerte-como-se-gesto-la-repatriacion-del-avion-鈥橾

Anotaciones y Ejercicios Curso de Web Scraping - Modulo II
Les dejo esta y todas las anotaciones del curso actualizados al 2023, tome nota de los comentarios y ejercicios resueltos de cada secci贸n. Lleve en cuenta las explicaciones del docente y m谩s! Espero les sirva. 馃憣
(si quieres apoyar deja una estrella a la repo 鉁屸瓙)

LES COMPARTO MI CODIGO ACTUALIZADO 2022 CON NUEVSO TAGS, ATRIBUTOS Y CLASSES

import pandas as pd
from bs4 import BeautifulSoup
import requests
import lxml.html as html

URL = 'https://www.pagina12.com.ar/'
def extract_soup_form(url):
    try:
        response = requests.get(url)
        if response.status_code == 200:
            s = BeautifulSoup(response.text, 'lxml')
            return s
        else:
            print('Status Code Error: => ', response.status_code)

    except ValueError as e:
        print('Error home links: =>', e)
def extract_home_links(s):
    try:
        sections_web = s.find('ul', attrs = {'class':'horizontal-list main-sections hide-on-dropdown'}).find_all('a')
        sections_list = [section.get('href') for section in sections_web]
        print('There are this Home Section Links: ====>: \n')
        print(sections_list)
        return sections_list

    except ValueError as e:
        print('Error: => ', e)
def extract_news_links(link, extract_soup_form):
    try:
        s = extract_soup_form(link)
        sections_web = s.find_all('div', attrs={'class': 'article-item__content'})
        sections_list= ['https://www.pagina12.com.ar'+section.p.a.get('href') for section in sections_web]
        print('\nThere are this Inside Section Links ===> \n')
        print(sections_list)
        return sections_list

    except ValueError as e:
        print('Error inside first link: =>' , e)
def main():
    s = extract_soup_form(URL)
    list_section_links=extract_home_links(s)
    inside_links=extract_news_links(list_section_links[0], extract_soup_form)
    
if __name__ == '__main__':
    main()

def pagina_12(url):
pagina = requests.get(url)
sopa = BeautifulSoup(pagina.text, 鈥榣xml鈥)
print(sopa.prettify())
secciones = sopa.find(鈥榰l鈥, attrs={鈥榗lass鈥: 鈥榤ain-sections鈥檥).find_all(鈥榣i鈥)
seccion = secciones[0]
seccion.a.get(鈥榟ref鈥)
links_secciones = [seccion.a.get(鈥榟ref鈥) for seccion in secciones]

return links_secciones
def analisis_section(objeto):
  total_articulos=[]
  article=objeto.find('section', attrs={'class':'col0'})
  articles=article.find_all('article')
  articulo=articles[0]
  link_articulo=[articulo.a.get('href') for articulo in articles]
  for i in link_articulo:
    link_final='https://www.eltiempo.com'+i
    total_articulos.append(link_final)
  
  print(total_articulos)

隆Reto resuelto con la estructura de la p谩gina en Octubre 2022!

import requests
from bs4 import BeautifulSoup

HOME_URL = 'https://www.pagina12.com.ar'


def parse_page(link):
    try:
        section = requests.get(link)
        if section.status_code == 200:
            pass
            #PARSE CURRENT PAGE
            soupSection = BeautifulSoup(section.text, 'lxml')
            #GET FEATURED ARTICLE
            featuredArticle = soupSection.find('h1', attrs={'class': 'title-list'})
            featuredLink = HOME_URL + featuredArticle.a.get('href')
            #GET HORIZONTAL ARTICLES
            articleListH = soupSection.find_all('h2', attrs={'class': 'title-list featured-article'})
            articleLinkH = [(HOME_URL + titleH.a.get('href')) for titleH in articleListH]
            #GET VERTICAL ARTICLES
            articleListV = soupSection.find_all('h2', attrs={'class': 'is-display-inline title-list'})
            articleLinkV = [(HOME_URL + titleV.a.get('href')) for titleV in articleListV]

            return(articleLinkH + articleLinkV)
        else:
            raise ValueError(f'Error: {section.status_code}')
    except ValueError as ve:
        print(ve)



def parse_home():
    try:
        response = requests.get(HOME_URL)
        if response.status_code == 200:
            soup = BeautifulSoup(response.text, 'lxml')
            #GET NAV LINKS
            listLinks = soup.find('ul', attrs = {'class': 'main-sections'}).find_all('li')
            link = listLinks[1].a.get('href')
            parse_page(link)
        else:
                raise ValueError(f'Error: {response.status_code}')
    except ValueError as ve:
        print(ve)


def run():
    parse_home()


if __name__=='__main__':
    run()

Reto

Mi aporte del reto utilizando un decorador, acepto feedback:

def link_web(func):
    """
    Funci贸n que recibe link de la p谩gina 
    y verifica la respuesta 200 OK.
    """
    def wrapper(url):
        try:
            request = requests.get(url)
            if request.status_code == 200:
                print('Respuesta OK')
                func(url)
            else:
                raise ValueError(f'Error: {request.status_code}')
        except ValueError as ve:
            print(ve)
    return wrapper


@link_web
def article_scraper(url):
    """
    Funci贸n que extrae el articulo y sus links
    """
    request = requests.get(url)
    web_body = BeautifulSoup(request.text, 'lxml')
    article = web_body.find('div', attrs={'class':'article-item__content-footer-wrapper gutter-small deco-bar-here-left is-mobile-top'})
    link_article = [url + article.a.get('href')]
    print(f'Noticia principal: {link_article}')
    article_second = web_body.find('div', attrs={
        'class':
        'articles-list is-grid-col2 grid-mobile-row'
    }).find_all('h2')
    links_seconds = [url + link.a.get('href') for link in article_second]
    print(f'Noticia secundaria: {links_seconds}')
    article_list = web_body.find('article', attrs={
        'class':
        'article-item article-item--teaser'
    }).find_all('h2')
    links_articles = [url + link.a.get('href') for link in article_list]
    print(f'Otros art铆culos: {links_articles}')

    return link_article + links_seconds + links_articles

Link utilizado:

pag = 'https://www.pagina12.com.ar/secciones/el-pais'
article_scraper(pag)

El texto tambi茅n se puede extraer como:

seccion.a.text

Arroja el mismo tipo de dato str, quiz谩 haya diferencia en tiempo de ejecuci贸n.

Reto resuelto

<def fnt_obtener_links(s):
    top_article = s.find('div', attrs={'class': 'article-item__content'})
    top_article_link = top_article.a.get('href')
    
    lista_h3 = s.find_all('h3', attrs={'class': 'title-list'})
    lista_links_seccion1 = [link.a.get('href') for link in lista_h3]
    
    lista_h2 = s.find_all('h2', attrs={'class': 'title-list'})
    lista_links_seccion2 = [link.a.get('href') for link in lista_h2]
    
    lista_links = [top_article_link] + lista_links_seccion1 + lista_links_seccion2
    
    return lista_links

import requests
from bs4 import BeautifulSoup

# resultado_request = requests.get('https://www.pagina12.com.ar/secciones/el-pais')
resultado_request = requests.get('https://www.pagina12.com.ar/secciones/el-pais')

s = BeautifulSoup(resultado_request.text, 'lxml') 

fnt_obtener_links(s)> 
def news(link):
    """
    Definici贸n: Extracci贸n de titulares y links de portal de noticias Argentino.
    
    Par谩metro: 
    -link: URL de la secci贸n de noticias a procesar.
    
    Retorno: T铆tulos y links de las noticias pertenecientes a ella.   
    """
    req = requests.get(link)
    soup = BeautifulSoup(req.text, "lxml")
    article_list = soup.find_all("h4", attrs={"class" : "is-display-inline title-list"})
    #Obtenemos los links de las noticias
    links_list = [link[:27]+article.a.get("href") for article in article_list]
    #Obtenemos los titulos de las noticias
    titles_list = [article.a.get_text() for article in article_list]
    return titles_list,links_list
def main(url:str):
  response = requests.get(url)

  if response.status_code == 200:
    s = BeautifulSoup(response.text, 'lxml')

    sections = s.find_all('h2')

    sections_links = [url + section.a.get('href') for section in sections]
    sections_links

    for link in sections_links:
      s_child = requests.get(link)

      article = BeautifulSoup(s_child.text, 'lxml')

      title = article.find('h1')

      print(title.get_text())

Debido al cambio del HTML de la pagina, as铆 me quedo el reto:

#Importacion de Librerias
import requests
from bs4 import BeautifulSoup

#Funciones
def GetLinks(ProtocolDomain, Soup):
    Notices=Soup.find_all('div',{'class','article-item__content'})
    Notices=[ProtocolDomain+ Notice.a.get('href') for Notice in Notices]
    return(Notices)

#Variables de Entrada
Links_sections='https://www.pagina12.com.ar/secciones/el-pais'
url='https://www.pagina12.com.ar'

#Preparacion de Variable
page = requests.get(Links_sections)
soup= BeautifulSoup(page.text,'lxml')

#Invocacion de Funcion
GetLinks(url, soup)

Reto cumplido:

import requests
from bs4 import BeautifulSoup

URL = 'https://www.pagina12.com.ar/secciones/el-pais'

def get_links_notices(url):
    """Funci贸n que recibe un URL de una categor铆a determinada de 
    la p谩gina web de noticias 'P谩gina 12' y devuelve los links de 
    todas las noticias pertenecientes a ella
    """
    
    soup = BeautifulSoup(requests.get(url).text,'lxml')
    
    # obtener url ra铆z
    main_url = url[:27]
    
    featured_article = soup.find('div', attrs={'class':'article-item__content'})
    featured_article_link = [main_url + featured_article.a.get('href')]
    
    article_content = soup.find_all('h3', attrs={'class':'title-list'})
    links_article_content = [main_url + links.a.get('href') for links in article_content]
    
    items_article = soup.find_all('div', attrs={'class':'article-item__header'})
    links_items_article = [main_url + links.a.get('href') for links in items_article]
    
    links = featured_article_link + links_article_content + links_items_article
    
    return links

get_links_notices(URL)

output

[鈥https://www.pagina12.com.ar/440247-denuncia-contra-la-corte-suprema-en-las-naciones-unidas鈥,
https://www.pagina12.com.ar/440245-rafecas-tendra-a-su-cargo-la-causa-por-el-ataque-al-institut鈥,
https://www.pagina12.com.ar/440236-miles-de-antorchas-por-evita-y-para-respaldar-al-gobierno-de鈥,
https://www.pagina12.com.ar/440247-denuncia-contra-la-corte-suprema-en-las-naciones-unidas鈥,
https://www.pagina12.com.ar/440245-rafecas-tendra-a-su-cargo-la-causa-por-el-ataque-al-institut鈥,
https://www.pagina12.com.ar/440236-miles-de-antorchas-por-evita-y-para-respaldar-al-gobierno-de鈥,
https://www.pagina12.com.ar/440232-evita-el-recuerdo-de-un-mito-inalterable鈥,
https://www.pagina12.com.ar/440225-la-tumba-de-evita-peron-donde-el-color-de-las-flores-avisa-q鈥,
https://www.pagina12.com.ar/440221-casa-rosada-todos-los-nombres-conducen-a-massa鈥,
https://www.pagina12.com.ar/440219-pese-a-su-caida-en-las-encuestas-el-sector-de-macri-no-renun鈥,
https://www.pagina12.com.ar/440211-ordenan-realizar-una-inspeccion-ocular-al-centro-clandestino鈥,
https://www.pagina12.com.ar/440201-potenciar-trabajo-bono-de-11-mil-pesos-a-1-3-millones-de-ben鈥,
https://www.pagina12.com.ar/440200-anuncian-la-construccion-de-nuevo-edificio-del-archivo-provi鈥,
https://www.pagina12.com.ar/440178-mario-negri-estaciono-su-auto-en-una-rampa-para-discapacitad鈥橾

Hola!
Aqu铆 va mi respuesta al reto, actualizado al 26/07/22

def get_links_noticias(seccion):

    main_article = seccion.find('section', attrs={'class':'top-content'}).find_all('h2')
    #Se usa url[0:-1] para quitar el 煤ltimo caracter de la url guardada anteriormente (https://www.pagina12.com.ar/)
    #y se concatena con el link de la noticia que est谩 en forma relativa.
    main_article_list = [url[0:-1]+ma.find('a').get('href') for ma in main_article]

    featured_articles = seccion.find_all('article', attrs={'class':'article-item--featured'})
    featured_article_list = [url[0:-1]+fa.find('h3').find('a').get('href') for fa in featured_articles]

    regular_articles = seccion.find_all('article', attrs={'class':'article-item article-item--teaser'})
    regular_articles_list = [url[0:-1]+ra.find('h4').find('a').get('href') for ra in regular_articles]

    links = main_article_list + featured_article_list + regular_articles_list

    return links
    
#En la lista de los link de secciones deportes corresponde a la posicion 4
seccion_deportes = BeautifulSoup(requests.get(link_secciones[4]).text, 'lxml')
get_links_noticias(seccion_deportes)

Encontr茅 tres formas diferentes de obtener los enlaces.

Con selectores CSS.

sections = soup.select('ul.main-sections>li>a')
{i.get_text(): i['href'] for i in sections}
[O] 
{'El pa铆s': 'https://www.pagina12.com.ar/secciones/el-pais',
 'Econom铆a': 'https://www.pagina12.com.ar/secciones/economia',
 'Sociedad': 'https://www.pagina12.com.ar/secciones/sociedad',
 'Cultura y Espect谩culos': 'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
 'Deportes': 'https://www.pagina12.com.ar/secciones/deportes',
 'El mundo': 'https://www.pagina12.com.ar/secciones/el-mundo',
 'Contratapa': 'https://www.pagina12.com.ar/secciones/contratapa'}

Con m茅todos de bs

sections = soup.find('ul', attrs={'class', 'main-sections'}).find_all('li')
dict(map(lambda section: (section.find('a').get_text(), section.find('a')['href']) ,sections ))
[O] ----------------------------------------
{'El pa铆s': 'https://www.pagina12.com.ar/secciones/el-pais',
 'Econom铆a': 'https://www.pagina12.com.ar/secciones/economia',
 'Sociedad': 'https://www.pagina12.com.ar/secciones/sociedad',
 'Cultura y Espect谩culos': 'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
 'Deportes': 'https://www.pagina12.com.ar/secciones/deportes',
 'El mundo': 'https://www.pagina12.com.ar/secciones/el-mundo',
 'Contratapa': 'https://www.pagina12.com.ar/secciones/contratapa'}

Con xpath

hhh = etree.HTML(str(soup))
sections = hhh.xpath(r'//ul[contains(@class, "main-sections")]/li/a')
dict(map(lambda x: (x.text, x.get('href')), sections))
[O] --------------------------------------------
{'El pa铆s': 'https://www.pagina12.com.ar/secciones/el-pais',
 'Econom铆a': 'https://www.pagina12.com.ar/secciones/economia',
 'Sociedad': 'https://www.pagina12.com.ar/secciones/sociedad',
 'Cultura y Espect谩culos': 'https://www.pagina12.com.ar/suplementos/cultura-y-espectaculos',
 'Deportes': 'https://www.pagina12.com.ar/secciones/deportes',
 'El mundo': 'https://www.pagina12.com.ar/secciones/el-mundo',
 'Contratapa': 'https://www.pagina12.com.ar/secciones/contratapa'}

Personalmente, prefiero utilizar los selectores CSS, son m谩s simples y el c贸digo queda en pocas l铆neas.

RETO

import requests
from bs4 import BeautifulSoup

pagina = requests.get('https://www.pagina12.com.ar/secciones/sociedad')
soup = BeautifulSoup(pagina.text,'lxml')

def get_links(soup):
    article_items = soup.find_all('article', attrs={'class':'article-item'})
    article_links = [item.a.get('href') for item in article_items]
    return article_links

get_links(soup)

""" Salida: 
 ['/426589-una-alianza-contra-elon-musk-en-twitter',
 '/426565-designan-otra-jefa-en-la-unidad-10-de-melchor-romero-que-alo',
 '/426544-garganta-del-diablo-se-suspendio-el-acceso-del-publico-por-l',
 '/416474-por-que-el-420-es-el-numero-de-la-marihuana',
 '/426516-murio-el-noba-tras-10-dias-internado-en-terapia-intensiva',
 '/426514-las-vegas-una-empresa-busca-impedir-que-imitadores-de-elvis-',
 '/426505-oms-el-cambio-climatico-tiene-fuerte-impacto-en-la-salud-men',
 '/424163-quien-era-el-noba-el-popular-musico-de-cumbia-420-que-murio-',
 '/426497-alberto-fernandez-a-siete-anos-del-primer-3-j-seguiremos-tra',
 '/426489-abre-al-publico-la-reserva-ecologica-de-costanera-norte',
 '/426053-efemerides-de-hoy-que-paso-un-3-de-junio'] """

Hola! Yo estoy siguiendo este curso pero con el proyecto de hacer web scrapping de la web IMDB, donde podemos observar el top de 250 pel铆culas. En este caso decid铆 extraer informaci贸n de: nombre de la pel铆cula, directores y protagonistas, a帽o de release, IMDB score y numero de votantes. Aqu铆 les dejo el c贸digo por donde va:

# Web Scrapper - IMDB Top 250 movies
import requests as rq
from bs4 import BeautifulSoup

# Saving the URL
url = 'https://www.imdb.com/chart/top/?ref_=nv_mv_250'

# Creating the request
page = rq.get(url)

# Making sure the web got the solicitude
page.status_code
print('The status of the request is: {}'.format(page.status_code))

# Creating the soup
soup = BeautifulSoup(page.text, 'lxml')

# Looks like the 'lister' tag has all the information we need
general = soup.find('div', attrs = {'class':'lister'})

# Now let's go deeper
general = soup.find('tbody', attrs= {'class':'lister-list'}).find_all('tr')

# All the information are in these tags, we just need to extract them!
# First, let's create a list with all the links

def link_creation(general):
    section = general[0]
    link_sections = [section.a.get('href') for section in general]
    index = 1
    common = '?pf_rd_m=A2FGELUUNOQJNL&pf_rd_p=1a264172-ae11-42e4-8ef7-7fed1973bb8f&pf_rd_r=MBY5AS7XQMWKBXS6Y8N7&pf_rd_s=center-1&pf_rd_t=15506&pf_rd_i=top&ref_=chttp_tt_'
    links = []
    for i in link_sections:
        link = ('www.imdb.com' + str(i) + common + str(index))
        links.append(link)
        index += 1
    
    return links

# Now let's create a list of movie names!

def movie_names(general):
    section = general[0]
    movie_names = [section.find('td', attrs = {'class':'titleColumn'}).a.get_text() for section in general]
    return movie_names

# And for everything else...

def categorics(general):
    section = general[0]
    ratings = [section.find('span', attrs = {'name':'ir'}).get('data-value') for section in general]
    qualifiers = [section.find('span', attrs = {'name':'nv'}).get('data-value') for section in general]
    year = [section.find('span', attrs = {'class':'secondaryInfo'}).get_text() for section in general]
    protagonist_dir = [section.find('td', attrs = {'class':'titleColumn'}).a.get('title') for section in general]

    return(section, ratings, qualifiers, year, protagonist_dir)

Mi get_article functions 馃槃

def get_articles(link_seccion): 
    sec = requests.get(link_seccion)
    if sec.status_code == 200:
        soup = BeautifulSoup(sec.text,'lxml')
        lister = soup.find_all('article')
        articulos = {lister[x].find_all('a')[1].get_text():lister[x].find_all('a')[1].get('href') for x in range(0,len(lister))}
        return articulos
    else:
        print('HTML code is not 200')

Estuve horas y no encontraba el error :麓v
Si el objeto.status_code te regresa un 403 como en mi caso no te va a salir la pr谩ctica. Si me percate que el DOM de la p谩gina hab铆a cambiado ligeramente y cre铆a que ah铆 esta el error, hasta que despu茅s de ver varias veces los videos, me di cuenta que la salida del objeto.text no correspond铆a del todo a la p谩g que solicitaba. Por lo que intente conseguir un c贸digo de status 200.
Investigando me di cuenta que si hacia uso de los encabezados de solicitud tal vez podr铆a arreglar el status de mi solicitud(En el video 4, minuto 5:50 obtuve una se帽al para solucionar el problema)
----C贸digo----
url = 'https://www.pagina12.com.ar/'
headers = {鈥榰ser-agent鈥: 鈥榤y-agent/1.0.1鈥檥
p12 = requests.get(url, headers=headers)

try:
    page =requests.get(url)
    if page.status_code == 200:
        soup = bs(page.text, "lxml")
        listUrl = list(soup.find_all("a"))
        for i in listUrl:   
            print(i.get("href"))
except (ValueError, IndexError):
    print("error")

pues alli le puse un poco de lo que tambien habia aprendido en anteriores cursos de platzi

si realizo estos procedimientos con Xpath, es peor o mejor que BeautifulSoup? o cual es la diferencia

Esta es mi resoluci贸n al reto, personalmente me gusta trabajar m谩s con select que con find, siento que es m谩s din谩mico.

Agregu茅 una peque帽a funci贸n map para agregar el hosntame a ciertos articulos que ven铆a el link sin el hostname.

Reto listo. Pagina de los art铆culos: https://www.pagina12.com.ar/secciones/el-pais

def soup(sopa):
    """Funcion que recive un objeto BS y retorna todos los links de los articulos que hay en la pagina"""
    articles = sopa.find_all('article',attrs={'class':'article-item'})
    links = [article.find('a').get('href') for article in articles]
    return links

No se si ustedes les paso pero la pagina que utiliza
cambio su estructura, es por eso que decid铆 hacerlo con la pagina del peri贸dico el Sol de M茅xico

Reto en la actualidad (13/12/21)

def links_section(url):
    pag = requests.get(url)
    if pag.status_code == 200:
        soup3 = BeautifulSoup(pag.text, 'lxml')
        links = soup3.select('.title-list a')
        href = [url + i.get('href') for i in links]
        print(href)
    else:
        print(f'P谩gina no responde Error: {pag.status_code}')

if __name__ == '__main__':
    url3 = "https://www.pagina12.com.ar/secciones/el-pais"
    links_section(url3)

Mi c贸digo (7/12/2021):

def extraer_links(link):
    pagina = requests.get(link)
    s_link = BeautifulSoup(pagina.text, 'lxml')
    s_noticiash2 = s_link.find_all('h2', attrs = {'class':'title-list'})
    s_noticiash3 = s_link.find_all('h3', attrs = {'class':'title-list'})
    s_noticiash4 = s_link.find_all('h4', attrs = {'class':'is-display-inline title-list'})
    s_noticias = s_noticiash2 + s_noticiash3 + s_noticiash4
    links_noticias = ['https://www.pagina12.com.ar' + seccion.find('a').get('href') for seccion in s_noticias]
    return links_noticias

Al d铆a de hoy. El div de la primera noticia se llama 鈥榓rticle-item__content鈥.

Al d铆a de hoy, 2021-11-10, la estructura de la p谩gina ha cambiado un poco. El c贸digo que me funci贸n queda as铆:

def links_category(sopa):
    ''' Input is a category page soup 
        and outputs are links '''
    
    link_feat_art = sopa.h2.a.get('href')

    #HTML text
    h3 = sopa.find_all('h3')
    h4 = sopa.find_all('h4')

    #lists

    links = []

    link_h2 = [link_feat_art]
    link_h3 = [x.a.get('href') for x in h3]
    link_h4 = [x.a.get('href') for x in h4 if x.a is not None]

    #Output

    links.extend(link_h2)
    links.extend(link_h3)
    links.extend(link_h4)

    links = ['https://www.pagina12.com.ar'+link for link in links]

    return links

Prob谩ndolo:

test = BeautifulSoup(requests.get('https://www.pagina12.com.ar/secciones/el-pais').text, 'lxml')
links_category(test)

Lo que me devuelve:

['https://www.pagina12.com.ar/381027-el-equipo-de-francisco',
 'https://www.pagina12.com.ar/381002-congelamiento-de-medicamentos-carla-vizzotti-y-roberto-felet',
 'https://www.pagina12.com.ar/380982-creamos-trabajo-queremos-derechos-movimientos-sociales-expon',
 'https://www.pagina12.com.ar/380963-el-frente-de-todos-porteno-cierra-la-campana-con-una-caravan',
 'https://www.pagina12.com.ar/366614-elecciones-2021-se-puede-cortar-boleta-este-14-de-noviembre',
 'https://www.pagina12.com.ar/380955-piden-la-indagatoria-de-mauricio-macri-por-el-destino-de-los',
 'https://www.pagina12.com.ar/380954-el-derrrumbe-de-otra-operacion-politica-del-macrismo-la-just',
 'https://www.pagina12.com.ar/360242-elecciones-2021-quienes-estan-exceptuados-por-covid-de-votar',
 'https://www.pagina12.com.ar/380950-cuales-son-los-requisitos-de-ingreso-al-pais-para-los-extran',
 'https://www.pagina12.com.ar/367149-elecciones-2021-cuando-empieza-la-veda-electoral-y-cuanto-ti',
 'https://www.pagina12.com.ar/380938-capturaron-a-roberto-brunello-un-represor-que-secuestro-tort']

Esta es de una p谩gina de noticias de Panam谩

import requests
from bs4 import BeautifulSoup
import lxml.html as html


def article_list(url,s):
    
    #haciendo el primer listado de links
    seccion = s.find('div', attrs={'class' : "nav" }).find_all('li')
    seccion0=seccion[0]
    links_secciones = [url+seccion0.a.get('href') for seccion0 in seccion]
    print(links_secciones)

    #Entrando en el primer link
    num= int(input('Ingrese el n煤mero de link que desea obtener sus links: '))
    sec = requests.get(links_secciones[num-1])

    #Haciendo el soup de la p谩gina buscada
    s_seccion = BeautifulSoup(sec.text, 'lxml')
    #print(s_seccion)
    
    #Art铆culo principal
    featured_art= s_seccion.find('div', attrs={'class' : "article-details con" })
    #print(featured_art)
    feat=url+featured_art.a.get('href')
    
    
    #Otros art铆culos
    article_list = s_seccion.find('div', attrs={'class':'category-secondary-sidebar'}).find_all('a')
    article_list0=article_list[0]
   
    
    links_secciones2 = [url+article_list0.get('href') for article_list0 in article_list]
   
    lista=[feat]
    lista.extend(links_secciones2)
    print(lista)



if __name__ == '__main__':
    url = 'https://www.laestrella.com.pa'

    p12=requests.get(url)
    print(p12.status_code)

    s=BeautifulSoup(p12.text, 'lxml')
    
    article_list(url,s)

Me he saltado un poco las reglas y lo he estado haciendo con una tienda, extrayendo el Titulo y el Precio

def obtener_notas(soup):
    lista_notas = []
    #Titulo del producto
    titulo = soup.find('h1', attrs={'class':'product_title entry-title'})
    if titulo:
        lista_notas.append(titulo.get_text())
    #Precio del producto
    precios = soup.find_all('bdi')
    precio = precios[2]
    if precios:
        lista_notas.append(precio.get_text())
    return lista_notas

obtener_notas(s_barril)
#OUT
['Barril Asador Ahumador Lamina de Hierro 10 Lb', 'COP $304,900.00']

Para resolver el reto he tenido en cuenta los casos en los que pod铆a fallar.

Este c贸digo v谩lido a 24/08/21.

import requests
from bs4 import BeautifulSoup

def news_links(soup):
    
    """
    @param BeautifulSoup soup
    @returns Array of soup's links
    """
    if soup is None:
        return []
    
    # Variables
    featured_article_link = []
    top_articles_links = []
    general_articles_links = []
    
    # Featured articles
    featured_article = soup.find('section', attrs={'class':'top-content'})
    if featured_article is not None:
        featured_article = featured_article.find('article')
        if featured_article is not None:
            featured_article = featured_article.find('h2')
            if featured_article is not None:
                featured_article = featured_article.find('a')
                if featured_article is not None:
                    featured_article_link = [featured_article.get('href')]
    
    # Rest of the articles in page
    articles_lists = soup.find('section', attrs={'class':'list-content'})
    if articles_lists is not None:
        articles_lists = articles_lists.find_all('div', {'class':'articles-list'})
    
        ## Top articles
        top_articles = articles_lists[0].find_all('article')
        if top_articles is not None:
            for article in top_articles:
                article = article.find('p', attrs={'class':'p12-separator--left--primary'})
                if article is not None:
                    article = article.find('a')
                    if article is not None:
                        top_articles_links += [article.get('href')]

        ## General articles
        general_articles = articles_lists[1].find_all('article')
        if general_articles is not None:
            for article in general_articles:
                article = article.find('a', attrs={'class':'p12-separator--left--primary'})
                if article is not None:
                    general_articles_links += [article.get('href')]
                        
    return featured_article_link + top_articles_links + general_articles_links

# Usage example
the_links = []

main_response = requests.get('https://www.pagina12.com.ar/')
s = BeautifulSoup(main_response.text, 'lxml')

sections = s.find('div', attrs={'class':'p12-dropdown-column'}).find_all('a')

for section in sections:
    response = requests.get(section.get('href'))
    soup = BeautifulSoup(response.text, 'lxml')
    the_links = the_links + news_links(soup)
    
the_links

guarde en una lista, listas donde almacene links de noticias segun su categoria , fueron 66 noticias, no se si sean todas

def seccion_link(obj, index):
    notices = obj.find_all('div' , attrs={'class':'article-item__content'})
    notices = [i.a.get('href') for i in notices]
    for i in notices:
        all_notices[index].append(i)
    


 
def search_link(obj):
    secciones = page.find('ul', attrs={'class':'horizontal-list main-sections hide-on-dropdown'}).find_all('li')
    links = [i.a.get('href') for i in secciones]

    for a,b in enumerate(links):
        all_notices.append([])
        category = requests.get(b)
        category = bs(category.text , 'lxml')
        seccion_link(category, a)
        
        
        
        
if __name__ == '__main__':
    search_link(page) 
    contador = 0
    for lista in all_notices:
        for i in lista:
            print(f'{i} \n')
            contador += 1
            
    print(contador)
        

Reto al 07-mayo-2021:

def get_article_links(soup):
    """ Receives a soup object and return the article links list"""
    articles = soup.find_all(attrs={'class': 'title-list'})
    return [article.a.get('href') for article in articles]

Ac谩 va el reto 馃槇:

from bs4 import BeautifulSoup
import requests


SECCION_URL = 'https://web.archive.org/web/20191111171336/https://www.pagina12.com.ar/secciones/el-pais'

NOTICIAS_PRINCIPALES_SELECTOR = '.featured-article__container > h2 > a'
NOTICIAS_SECUNDARIAS_SELECTOR = '.article-box__container > h2 > a'


def seleccionar_noticias(seccion_soup, noticias_selector):
    return seccion_soup.select(noticias_selector)


def noticias_principales(seccion_soup):
    return seleccionar_noticias(seccion_soup, NOTICIAS_PRINCIPALES_SELECTOR)


def noticias_secundarias(seccion_soup):
    return seleccionar_noticias(seccion_soup, NOTICIAS_SECUNDARIAS_SELECTOR)


def obtener_links(noticias_soup):
    links = map(lambda noticia: noticia.get('href'), noticias_soup)
    return list(links)


def obtener_links_de_las_noticias(seccion_soup):
    """
    Recibe una sopa de una secci贸n de noticias.
    Retorna los links de las noticias.
    """
    noticias = noticias_principales(seccion_soup) +\
        noticias_secundarias(seccion_soup)

    return obtener_links(noticias)


def main():
    """ Ejemplo de uso """
    p12_request = requests.get(SECCION_URL)
    p12_html = p12_request.text

    seccion_soup = BeautifulSoup(p12_html, 'lxml')

    links = obtener_links_de_las_noticias(seccion_soup)

    for indice, link in enumerate(links):
        print(f"Noticia {indice}: {link}")
        print("-" * 50)


if __name__ == '__main__':
    main()

Reto cumplido

import requests
from bs4 import BeautifulSoup

response = requests.get('https://www.pagina12.com.ar/')
s = BeautifulSoup(response.text, 'lxml')
secciones = s.find('ul',attrs={'class':'horizontal-list main-sections hide-on-dropdown'}).find_all('li')
seccion = secciones[0]
link_secciones = [seccion.a.get('href') for seccion in secciones]
sec = requests.get(link_secciones[5])
soup = BeautifulSoup(sec.text, 'lxml')

def notice(soup):
 
    Article_list = soup.find_all('div', attrs = {'class':'article-item__content'})

    links_Article= [link.find('a').get('href') for link in Article_list]
    
    return links_Article
    
if __name__ == '__main__':
    a = notice(soup)
    for links in a:
        print(links)

Con las modificaciones que le hicieron a la p谩gina 2021

def noticias_por_seccion (seccion ):
	"""Debe recibir un link ya pharseado lxml"""
	noticia_lista_links = seccion.find_all('article')
	noticia_lista_links = [noticia.a.get('href') for noticia in noticia_lista_links]
return noticia_lista_links

A mi me sirvieron las siguientes l铆neas para resolver el tema:

links = [item.get('href') for item in secciones]
texto = [item.get_text() for item in secciones]

Hola a todos, por ac谩 les dejo un link donde pueden descargar la versi贸n del notebook que estoy contruyendo a medida que el curso avanza.

https://drive.google.com/file/d/1V5tttkZWpSnu2yqR3Cfs0s4STqOkzcMV/view?usp=sharing

para la comunidad si tienen erro al momento de realizar el boc = requests.get(LinkBocon[0]) es por que si se fijan bien no tiene https:// entonces para poder invocar a esa funcion le ayudamos poniendo el nimbre de la pagina /2pagina
boc = requests.get(鈥https://elbocon.pe鈥+LinkBocon[1])

Este es el c贸digo en Jupiter Notebook

import requests
url = 'https://www.pagina12.com.ar/'
p12 = requests.get(url)
p12.status_code
p12.content
p12.request.url
from bs4 import BeautifulSoup
s = BeautifulSoup(p12.text, 'lxml')
secciones = s.find('ul', attrs={'class':'horizontal-list main-sections hide-on-dropdown'}).find_all('li')
links_secciones = [seccion.a.get('href') for seccion in secciones]
sec = requests.get(links_secciones[0])
s_seccion = BeautifulSoup(sec.text, 'lxml')
article_list = s_seccion.find('div', attrs={'class':'articles-list is-grid-col2 grid-mobile-row'})
articles = s_seccion.find('div', attrs={'class':'article-item__content-footer-wrapper gutter-small deco-bar-here-left'}).find_all('h4', attrs={'class':not ''})
links_articles = [article.a.get('href') for article in articles]
links_articles

https://www.pagina12.com.ar/304090-que-es-el-dispo-y-que-cambia-respecto-al-aspo鈥,
https://www.pagina12.com.ar/304075-el-gobierno-prepara-el-paso-del-aislamiento-al-distanciamien鈥,
https://www.pagina12.com.ar/304062-declaran-de-interes-publico-las-vacunas-contra-el-coronaviru鈥,
https://www.pagina12.com.ar/304060-habilitan-la-vuelta-a-clases-presenciales-en-las-universidad鈥,
https://www.pagina12.com.ar/304031-como-sera-la-caravana-del-retorno-a-la-patria-de-evo-morales鈥,
https://www.pagina12.com.ar/304028-por-un-sistema-de-medios-publicos-con-perspectiva-de-genero鈥,
https://www.pagina12.com.ar/304013-santiago-cafiero-sigue-siendo-una-posibilidad-enviar-este-an鈥,
'https://www.pagina12.com.ar/304009-formalizaron-el-primer-ingreso-al-programa-de-empleo-trans-e

驴Alguien sabe porqu茅 me aparece 茅ste error?

Challenge:

def articles_links(soup):
    articles_featured = soup.find('section', attrs={'class':'top-content'}).find_all('h2') 
    articles_h3 = soup.find('section', attrs={'class':'list-content'}).find_all('h3')
    articles_h4 = soup.find('section', attrs={'class':'list-content'}).find_all('h4', attrs={'class':'is-display-inline title-list'})
    links_featured = [article.a.get('href') for article in articles_featured]
    links_h3 = [article.a.get('href') for article in articles_h3]
    links_h4 = [article.a.get('href') for article in articles_h4]
    print(links_featured, links_h3, links_h4)

Ayuda me sale este error

<code>
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-14-befa6dea293b> in <module>
----> 1 secciones = s.find('ul', attrs={'class':'hot-sections'}).find_all('li')
      2 secciones

AttributeError: 'NoneType' object has no attribute 'find_all'
<code>

Reto resuelto!

def extract_links_p12(soup):
    """
    Funci贸n que recibe un objeto de tipo BeautifulSoup de una categor铆a de P谩gina12, y devuelve un diccionario con el nombre del art铆culo y su enlace.
    """
    soup_list = soup.find('ul', attrs = {'class':'article-list'}).find_all('div', attrs = {'class': 'article-box-sections'})
    links = [l.a.get('href') for l in soup_list]
    descriptions = [l.a.get_text() for l in soup_list]
    dict_description = {description:link for description, link in zip(descriptions, links)}
    return dict_description

# Usandolo con la p谩gina de econom铆a el 03/09/2020

{'Preventivo de crisis|Atento Argentina': 'https://www.pagina12.com.ar/289727-preventivo-de-crisis',
 'Reactivan la construcci贸n en CABA|Para obras de m谩s de 5000 m2 y pr贸ximas a su finalizaci贸n': 'https://www.pagina12.com.ar/289723-reactivan-la-construccion-en-caba',
 'Alberto Fern谩ndez: "Necesitamos que cada autoparte la produzca una pyme"|La apuesta a la integraci贸n nacional en la producci贸n automotriz': 'https://www.pagina12.com.ar/289701-alberto-fernandez-necesitamos-que-cada-autoparte-la-produzca',
 'Sectores con buenos n煤meros\xa0|Materiales, cosechadoras, l铆nea blanca y textiles': 'https://www.pagina12.com.ar/289688-sectores-con-buenos-numeros',
 'Cr铆ticas a la toma de tierras|"Es un delito", asegur贸 Bianco': 'https://www.pagina12.com.ar/289686-criticas-a-la-toma-de-tierras',
 'Bianco: "Las salidas a estas crisis siempre vinieron de la mano del Estado"|Entrevista al jefe de Gabinete del gobierno de la Provincia de Buenos Aires': 'https://www.pagina12.com.ar/289680-bianco-las-salidas-a-estas-crisis-siempre-vinieron-de-la-man',
 'Est铆mulos para recuperar la producci贸n y el empleo industrial|"Vemos a varios sectores firmes en la generaci贸n de trabajo", afirm贸 el secretario del 谩rea, Ariel Schale': 'https://www.pagina12.com.ar/289677-estimulos-para-recuperar-la-produccion-y-el-empleo-industria',
 'La producci贸n de autos se recupera y busca llegar a niveles pre pandemia|La comparaci贸n contra el 2019 sigue siendo negativa': 'https://www.pagina12.com.ar/289658-la-produccion-de-autos-se-recupera-y-busca-llegar-a-niveles-',
 'El congelamiento de alquileres se prorroga\xa0|El presidente Alberto Fern谩ndez confirmque trabajan en una extensi贸n de la medida': 'https://www.pagina12.com.ar/289652-el-congelamiento-de-alquileres-se-prorroga',
 'Enacom con grandes empresas: el lado B de la pirotecnia medi谩tica\xa0|La regulaci贸n de internet, celulares y TV por cable': 'https://www.pagina12.com.ar/289610-enacom-con-grandes-empresas-el-lado-b-de-la-pirotecnia-media',
 'La recaudaci贸n se recupera de a poco|Registr贸 en agosto una suba interanual del 33,5 por ciento': 'https://www.pagina12.com.ar/289385-la-recaudacion-se-recupera-de-a-poco',
 'La bolsa en baja|Retrocedi贸 3,6 por ciento': 'https://www.pagina12.com.ar/289388-la-bolsa-en-baja',
 'Impulso a la industria para comenzar a crecer|Anuncios del ministro de Desarrollo Productivo, Matas Kulfas': 'https://www.pagina12.com.ar/289393-impulso-a-la-industria-para-comenzar-a-crecer',
 'El IFE y la toma de tierras|Raverta dijo que no se constat贸 un v铆nculo': 'https://www.pagina12.com.ar/289414-el-ife-y-la-toma-de-tierras'}
def links_function(BS):
    featured_article = BS.find('div', attrs = {'class':'featured-article__container'})
    featured_article = featured_article.a.get('href')
    article_list = BS.find('ul', attrs = {'class':'article-list'})
    sub_articulos = article_list.find_all('h2')
    links_sub_articulos = [ sub_articulo.a.get('href') for sub_articulo in sub_articulos]
    print('el articulo principal de la seccion es: \n', featured_article)
    print('los articulos secundarios son:\n')
    print ('{}:{}'.format(i,links_sub_articulos[i]) for i in enumerate(links_sub_articulos))

Mi solucion

def get_links_article_page(beautifulSoup):
    links = []

    ul_tag = beautifulSoup.find('ul', attrs={'class':'article-list'})
    h2_list = ul_tag.find_all('h2')
    
    for h2 in h2_list:
        a = h2.find('a').get('href')
        links.append(a)

    return links

Mi solucion al reto:


import requests 
import bs4
from bs4 import BeautifulSoup
def get_link(link):
    articulo = link.find('ul', attrs={'class':'article-list'}).find_all('h2')
    sec = articulo[0]
    sec.find('a')
    #art = link.find('div', attrs={'class':'article-box__container'})
    link_articulo = [sec.a.get('href') for sec in articulo]
    return(link_articulo)
if __name__ == '__main__':
    url = input('ingrese el url: ')
    pagina = requests.get(url)
    s = BeautifulSoup(pagina.text, 'lxml')
    lin = get_link(s)
    for i in lin:
        print(i)```

Mi soluci贸n:

def get_article_links(soup):
    article_links = []
    # El art铆culo promocionado
    featured_article = soup_seccion.find('div', attrs={'class': 'featured-article__container'})
    featured_article_link = featured_article.find('h2').a.get('href')
    article_links.append(featured_article_link)
    
    # La lista de abajo
    article_list = soup_seccion.find('ul', attrs={'class': 'article-list'})
    article_list = article_list.find_all('div', 'article-box__container')
    [article_links.append(article.h2.a.get('href')) for article in article_list]
    return article_links

Trato de hacer un for con el text y no me funciona.
C脫DIGO:

texts = [t.a.get_text() for t in td]

AttributeError Traceback (most recent call last)
<ipython-input-28-f56178ad35a3> in <module>
----> 1 texts = [t.a.get_text() for t in td]

<ipython-input-28-f56178ad35a3> in <listcomp>(.0)
----> 1 texts = [t.a.get_text() for t in td]

AttributeError: 鈥楴oneType鈥 object has no attribute 鈥榞et_text鈥

Mi soluci贸n

def showNews( objBs4SectionPage: BeautifulSoup ):
    featured_article= s_seccion.find('div', attrs={'class':'featured-article__container'})
    featured_article
    print(featured_article.a.get('href'))
    article_list = s_seccion.find('ul', attrs={'class':'article-list'})

    list_featured_articles = article_list.find_all('h2')
    links_featured_articles = [ articles.a.get('href') for articles in list_featured_articles]
    for link in links_featured_articles :
        print(link)
        
return;

Al ejecutar

showNews(s_seccion)

Obtenemos

https://www.pagina12.com.ar/237129-orcar-laborde-presidira-el-parlasur
https://www.pagina12.com.ar/237005-las-retenciones-de-vuelta-la-burra-al-trigo
https://www.pagina12.com.ar/237133-con-la-mirada-puesta-en-la-camara-baja
https://www.pagina12.com.ar/237144-alberto-fernandez-recibio-a-daniel-rafecas
https://www.pagina12.com.ar/237168-sin-memoria
https://www.pagina12.com.ar/237067-en-el-senado-el-macrismo-pierde-una-integrante
https://www.pagina12.com.ar/237075-dictadura-proyecto-para-reparar-legajos-de-trabajadores-desa
https://www.pagina12.com.ar/237086-hacia-la-emergencia-bonaerense
https://www.pagina12.com.ar/237091-lange-de-falcone-fue-desplazada-de-la-presidencia-de-la-cort
https://www.pagina12.com.ar/237099-peajes-una-empresa-que-estuvo-vinculada-a-los-macri-se-acogi
https://www.pagina12.com.ar/237100-sospechas-sobre-carrio-allanamiento-en-la-afip
https://www.pagina12.com.ar/237101-la-solidaridad-de-la-cgt
https://www.pagina12.com.ar/237118-primer-encuentro-del-pro-tras-la-derrota
https://www.pagina12.com.ar/237122-el-pacto-fiscal-de-macri-paso-a-mejor-vida
https://www.pagina12.com.ar/237127-el-macrismo-no-dara-quorum-y-votara-en-contra-de-la-ley-de-s

Mi soluci贸n particular, partiendo de tener el link de la secci贸n como un objeto de bs4

def get_article_links(bs4_object):
    # Parse Featured article
    featured_article = (bs4_object.find(
        'div', attrs={'class': 'featured-article__container'}).a.get('href'))

    # Parse Article List block
    article_list_data = bs4_object.find('ul', attrs={'class': 'article-list'})
    article_links = [article.a.get('href')
                    for article in article_list_data if article.a != None]

    return [featured_article, *article_links]


get_article_links(s_seccion)