Красивый суп: извлечение текста и URL-адресов из списка, но только под определенными заголовками

#python #html #web-scraping #beautifulsoup

#python #HTML #очистка веб-страниц #beautifulsoup

Вопрос:

Я хочу использовать Beautiful Soup для очистки страницы обновлений новостей Fujitsu: https://www.fujitsu.com/uk/news/pr/2020 /

Я хочу извлечь информацию только под заголовками текущего месяца и предыдущего месяца.

Для определенного месяца (например, ноября) я пытаюсь извлечь в список

  • заголовок
  • URL-адрес
  • текст

для каждого новостного брифинга (таким образом, список списков).

Моя попытка пока выглядит следующим образом (для простоты показан только предыдущий месяц):

 today = datetime.datetime.today()
year_str = str(today.year) 

current_m = today.month
previous_m = current_m - 1
current_m_str = calendar.month_name[current_m]
previous_m_str = calendar.month_name[previous_m]

URL = 'https://www.fujitsu.com/uk/news/pr/'   year_str   '/'
resp = requests.get(URL)
soup = BeautifulSoup(resp.text, 'lxml')

previous_m_body = soup.find('h3', text=previous_m_str)
if previous_m_body is not None:
    for sib in previous_m_body.find_next_siblings():
        if sib.name == "h3":
            break
        else:
            previous_m_text = str(sib.text)
            print(previous_m_text)
 

Однако при этом генерируется одна длинная строка с новыми строками и без разделения между заголовком, текстом, url:

Fujitsu подписывает крупный контракт с правительством Шотландии на поставку решения для электронного подсчета голосов на выборах Лондон, Великобритания, 30 ноября 2020 г. — Fujitsu, ведущая компания по цифровым преобразованиям, сегодня объявила о крупном контракте с правительством Шотландии и местным населением Шотландии…

Fujitsu представляет ультракомпактное реле на печатной плате на 50 А для средне- и тяжеловесных автомобильных нагрузок Хофддорп, EMEA, 11 ноября 2020 г. — Fujitsu Components Europe расширила ассортимент автомобильных реле, добавив новое реле на печатной плате 12 В постоянного тока…….

Я прикрепил изображение страницы DOM.

Ответ №1:

Попробуйте это:

 import requests
from bs4 import BeautifulSoup

html = requests.get("https://www.fujitsu.com/uk/news/pr/2020/").text
all_lists = BeautifulSoup(html, "html.parser").find_all("ul", class_="filterlist")

news = []
for unordered_list in all_lists:
    for list_item in unordered_list.find_all("li"):
        news.append(
            [
                list_item.find("a").getText(),
                f"https://www.fujitsu.com{list_item.find('a')['href']}",
                list_item.getText(strip=True)[len(list_item.find("a").getText()):],
            ]
        )

for news_item in news:
    print("n".join(news_item))
    print("-" * 80)
 

Вывод (сокращенный для краткости):

 Fujitsu signs major contract with Scottish Government to deliver election e-Counting solution
https://www.fujitsu.com/uk/news/pr/2020/fs-20201130.html
London, United Kingdom, November 30, 2020- Fujitsu, a leading digital transformation company, has today announced a major contract with the Scottish Government and Scottish Local Authorities to support the electronic counting (e-Counting) of ballot papers at the Scottish Local Government elections in May 2022.Fujitsu Introduces Ultra-Compact, 50A PCB Relay for Medium-to-Heavy Automotive LoadsHoofddorp, EMEA, November 11, 2020- Fujitsu Components Europe has expanded its automotive relay offering with a new 12VDC PCB relay featuring a switching capacity of 50A at 14VDC. The FBR53-HC offers a higher contact rating than its 40A FBR53-HW counterpart, yet occupies the same 12.1 x 15.5 x 13.7mm footprint and weighs the same 6g.
--------------------------------------------------------------------------------

and more ...
 

Редактировать:

Чтобы получить только последние два месяца, все, что вам нужно, это первые два ul элемента из soup . Итак, добавьте [:2] к первому for loop , вот так:

 for unordered_list in all_lists[:2]:
    # the rest of the loop body goes here
 

Комментарии:

1. Привет — большое спасибо за ответ. Похоже, это работает, но только для первой новости в каждом месяце (вплоть до января 2020 года) Как я могу изменить это, чтобы извлечь все новости за текущий и предыдущий месяц?

2. Я думаю, это потому, что, хотя «суп» содержит 10 элементов ul (10 разных месяцев), каждый из них содержит 1 или более новостных элементов, но цикл for извлекает только первый экземпляр ‘a’, href и сводный текст?

Ответ №2:

здесь я изменил ваш код. Я объединил ваш код bs4 с selenium. Selenium очень эффективен для создания динамического веб-сайта или веб-сайта на основе JavaScript. Вы можете использовать selenium с BeautifulSoup, чтобы упростить себе жизнь. Теперь он выдаст вам выходные данные за все месяцы.

     from selenium import webdriver
    from bs4 import BeautifulSoup
    
    
    driver =  webdriver.Firefox()
    driver.maximize_window()
    
    url = "https://www.fujitsu.com/uk/news/pr/2020/" #change the url if you want to get result for different year
    
    driver.get(url)
    
   # now your bs4 code start. It will give you output from current month to previous all month
    soup = BeautifulSoup(driver.page_source, "html.parser") 
    
    #here I am getting all month name from January to november.  
    months = soup.find_all('h3')
    
    for month in months:
            month = month.text
            print(f"month_name : {month}n")
    #here we are getting all description text from current month to all previous months 
    description_texts = soup.find_all('ul',class_='filterlist')
    for description_text in description_texts:
        description_texts = description_text.text.replace('n','')
        print(f"description_text: {description_texts}")
 

вывод:
введите описание изображения здесь

Комментарии:

1. Использование selenium в этом случае — просто перебор.