Керівництво зі скрапінгу Google News за допомогою Python

Коментарі: 0

Скрапінг Google News може бути вкрай корисним для збору даних про останні новинні заголовки, і моніторингу трендів у новинах для проведення їхнього аналізу. У цій статті ми покажемо, як здійснювати скрапінг Google News з використанням Python. Для цього скористаємося бібліотекою requests для отримання вмісту сторінки та lxml для парсингу HTML і вилучення необхідних даних.

Крок 1: Налаштування середовища

Перш ніж почати, переконайтеся, що на вашому комп'ютері встановлено Python. Для встановлення необхідних бібліотек виконайте такі команди:


pip install requests 
pip install lxml

Ці бібліотеки дадуть змогу надсилати HTTP-запити й аналізувати HTML-вміст веб-сторінок.

Крок 2: Розуміння цільового URL і структури XPath

Для скрапінгу буде використовуватися сторінка Google News, що містить безліч новинних статей:


URL = "https://news.google.com/topics/CAAqKggKIiRDQkFTRlFvSUwyMHZNRGRqTVhZU0JXVnVMVWRDR2dKSlRpZ0FQAQ?hl=en-US&gl=US&ceid=US%3Aen"

Кожна з новин містить основний заголовок і пов'язані статті. Структуру XPath для цих елементів представлено таким чином:

  • Контейнер основних новин: //c-wiz[@jsrenderer="ARwRbe"];
  • Основний заголовок новин://c-wiz[@jsrenderer="ARwRbe"]/c-wiz/div/article/a/text();
  • Посилання на основні новини://c-wiz[@jsrenderer="ARwRbe"]/c-wiz/div/article/a/@href;
  • Контейнер пов'язаних новин://c-wiz[@jsrenderer="ARwRbe"]/c-wiz/div/div/article/;
  • Заголовки пов'язаних новин://c-wiz[@jsrenderer="ARwRbe"]/c-wiz/div/div/article/a/text();
  • Посилання на пов'язані новини://c-wiz[@jsrenderer="ARwRbe"]/c-wiz/div/div/article/a/@href.

HTML-структура сайту Google News не змінюється між сторінками, тому перераховані XPath-елементи будуть актуальні для кожної з них.

Крок 3: Витяг вмісту сторінки Google News

Процес починається із запиту сторінки Google News із використанням бібліотеки requests. Нижче наведено код для отримання HTML-контенту сторінки:


import requests

url = "https://news.google.com/topics/CAAqKggKIiRDQkFTRlFvSUwyMHZNRGRqTVhZU0JXVnVMVWRDR2dKSlRpZ0FQAQ?hl=en-US&gl=US&ceid=US%3Aen"
response = requests.get(url)

if response.status_code == 200:
    page_content = response.content
else:
    print(f"Failed to retrieve the page. Status code: {response.status_code}")

У цьому прикладі, якщо HTTP-запит успішний, вміст сторінки зберігається у змінній page_content. Це дає змогу далі працювати з HTML-контентом для вилучення даних.

Крок 4: Парсинг HTML-вмісту за допомогою lxml

Після отримання HTML-вмісту сторінки, наступний крок - його аналіз за допомогою бібліотеки lxml для вилучення необхідної інформації, такої як заголовки новин і відповідні посилання.


from lxml import html

# Парсинг HTML-вмісту
parser = html.fromstring(page_content)

Крок 5: Витяг новинних даних

Після успішного парсингу HTML-сторінки, наступний етап полягає у вилученні інформації з контейнерів новин на Google News. Це робиться шляхом використання XPath для локалізації цих контейнерів і подальшого доступу до заголовків новин та їхніх посилань усередині кожного контейнера.

Витяг основних новинних статей

Для отримання даних з основних новинних статей, спочатку необхідно визначити їхнє розташування в HTML-структурі сторінки Google News з використанням XPath.


main_news_elements = parser.xpath('//c-wiz[@jsrenderer="ARwRbe"]')

Після визначення коректного XPath, можна перейти до вилучення заголовків і посилань перших десяти статей.


news_data = []

for element in main_news_elements[:10]:
    title = element.xpath('.//c-wiz/div/article/a/text()')[0]
    link = "https://news.google.com" + element.xpath('.//c-wiz/div/article/a/@href')[0][1:]

    
    # Переконайтеся, що дані існують, перш ніж додавати їх до списку
    if title and link:
        news_data.append({
        "main_title": title,
        "main_link": link,
    })

Витяг пов'язаних статей у кожному основному новинному елементі

Для того щоб витягти пов'язані статті всередині кожного основного новинного елемента, використовується метод, аналогічний тому, що застосовувався для вилучення основних статей. Нижче представлено підхід, що дає змогу отримати пов'язані статті з кожного основного новинного блоку:


related_articles = []
related_news_elements = element.xpath('.//c-wiz/div/div/article')

for related_element in related_news_elements:
    related_title = related_element.xpath('.//a/text()')[0]
    related_link = "https://news.google.com" + related_element.xpath('.//a/@href')[0][1:]
    related_articles.append({"title": related_title, "link": related_link})

news_data.append({
    "main_title": title,
    "main_link": link,
    "related_articles": related_articles
})

Збереження даних у форматі JSON

Після вилучення даних їх можна зберегти у файлі JSON для подальшого використання.


import json

with open('google_news_data.json', 'w') as f:
    json.dump(news_data, f, indent=4)

Код створить файл з ім'ям google_news_data.json, що містить усі витягнуті заголовки новин і відповідні їм посилання.

Використання проксі

Використання проксі є ефективним рішенням для уникнення блокувань IP-адрес і обмежень на частоту запитів під час скрапінгу сайтів із високою відвідуваністю, таких як Google News. Проксі дають змогу маршрутизувати запити через різні IP-адреси, що ускладнює виявлення і блокування активності скрапінгу. Нижче наведено приклад налаштування проксі в запитах Python з використанням бібліотеки requests:


proxies = {
    "http": "http://your_proxy_ip:port",
    "https": "https://your_proxy_ip:port",
}

response = requests.get(url, proxies=proxies)

Якщо ви використовуєте сервіс, який керує ротацією проксі, вам необхідно тільки включити параметри проксі у ваші запити. Сервіс автоматично оброблятиме ротацію IP-адрес, мінімізуючи ризик блокування.

Налаштування заголовків запитів для уникнення виявлення

Деякі сайти можуть відхиляти запити, якщо в них відсутні певні заголовки, як-от User-Agent, який ідентифікує запити, що надходять із браузерів. Налаштування заголовків дає змогу імітувати запити, які надходять від реальних користувачів, тим самим знижуючи ймовірність виявлення скрапінгу.


headers = {
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'accept-language': 'en-IN,en;q=0.9',
    'cache-control': 'no-cache',
    'dnt': '1',
    'pragma': 'no-cache',
    'priority': 'u=0, i',
    'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
    'sec-ch-ua-arch': '"x86"',
    'sec-ch-ua-bitness': '"64"',
    'sec-ch-ua-full-version-list': '"Not)A;Brand";v="99.0.0.0", "Google Chrome";v="127.0.6533.72", "Chromium";v="127.0.6533.72"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-model': '""',
    'sec-ch-ua-platform': '"Linux"',
    'sec-ch-ua-platform-version': '"6.5.0"',
    'sec-ch-ua-wow64': '?0',
    'sec-fetch-dest': 'document',
    'sec-fetch-mode': 'navigate',
    'sec-fetch-site': 'none',
    'sec-fetch-user': '?1',
    'upgrade-insecure-requests': '1',
    'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
}

response = requests.get(url, headers=headers)

Фінальна версія коду


import requests
import urllib3
from lxml import html
import json

urllib3.disable_warnings()

# URL і заголовки
url = "https://news.google.com/topics/CAAqKggKIiRDQkFTRlFvSUwyMHZNRGRqTVhZU0JXVnVMVWRDR2dKSlRpZ0FQAQ?hl=en-US&gl=US&ceid=US%3Aen"
headers = {
   'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
   'accept-language': 'en-IN,en;q=0.9',
   'cache-control': 'no-cache',
   'dnt': '1',
   'pragma': 'no-cache',
   'priority': 'u=0, i',
   'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
   'sec-ch-ua-arch': '"x86"',
   'sec-ch-ua-bitness': '"64"',
   'sec-ch-ua-full-version-list': '"Not)A;Brand";v="99.0.0.0", "Google Chrome";v="127.0.6533.72", "Chromium";v="127.0.6533.72"',
   'sec-ch-ua-mobile': '?0',
   'sec-ch-ua-model': '""',
   'sec-ch-ua-platform': '"Linux"',
   'sec-ch-ua-platform-version': '"6.5.0"',
   'sec-ch-ua-wow64': '?0',
   'sec-fetch-dest': 'document',
   'sec-fetch-mode': 'navigate',
   'sec-fetch-site': 'none',
   'sec-fetch-user': '?1',
   'upgrade-insecure-requests': '1',
   'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
}

# Конфігурація проксі
proxy = 'ip:port'
proxies = {
   "http": f"http://{proxy}",
   "https": f"https://{proxy}",
}

# Надсилання GET-запиту для отримання вмісту HTML
response = requests.get(url, headers=headers, proxies=proxies, verify=False)

# Перевірка успішності запиту
if response.status_code == 200:
   page_content = response.content
else:
   print(f"Failed to retrieve the page. Status code: {response.status_code}")
   exit()

# Парсинг HTML-вмісту за допомогою lxml
parser = html.fromstring(page_content)

# Витяг елементів основних новин і пов'язаних статей
main_news_elements = parser.xpath('//*[@id="i10-panel"]/c-wiz/c-wiz')

# Ініціалізація списку для збереження витягнутих даних
news_data = []

# Перебір кожного елемента основної новини
for element in main_news_elements[:10]:
   # Витяг заголовка та посилання основної новини
   title = element.xpath('.//c-wiz/div/article/a/text()')
   link = element.xpath('.//c-wiz/div/article/a/@href')

   # Ініціалізація списку для збереження пов'язаних статей цієї новини
   related_articles = []

   # Витяг елементів пов'язаних новин у тому самому блоці
   related_news_elements = element.xpath('.//c-wiz/div/div/article')

   # Перебір кожного елемента пов'язаної новини та витяг заголовка і посилання
   for related_element in related_news_elements:
       related_title = related_element.xpath('.//a/text()')[0]
       related_link = "https://news.google.com" + related_element.xpath('.//a/@href')[0][1:]
       related_articles.append({"title": related_title, "link": related_link})

   # Додавання основної новини та її пов'язаних статей до списку даних
   if title is not None:
       news_data.append({
           "main_title": title,
           "main_link": f'https://news.google.com{link}',
           "related_articles": related_articles
       })
   else:
       continue


# Збереження витягнутих даних у файл JSON
with open("google_news_data.json", "w") as json_file:
   json.dump(news_data, json_file, indent=4)

print('Data extraction complete. Saved to google_news_data.json')

Скрапінг Google News за допомогою Python і бібліотек requests і lxml дає змогу глибоко аналізувати новинні тренди. Важливо використовувати проксі та налаштувати заголовки запитів для запобігання блокувань і забезпечення стабільності роботи скрапера. Проксі, які найбільше підходять для веб-скрапінгу: датацентр IPv4 і IPv6, ISP проксі, які забезпечують високу швидкість з'єднання і низький пінг, а також динамічні резидентські проксі з найвищим показником траст-фактора.

Коментарії:

0 Коментаріїв