Руководство по извлечению данных о позиции, заголовке, ссылке, отображаемой ссылке, фрагменте и значке значка из Qwant с использованием Python.
👉Кратко о сути: обучающий пост в блоге о парсинге: позиция сайта для отслеживания SEO-рейтинга, заголовок, ссылка, отображаемая ссылка, сниппет и данные фавикона из результатов поиска qwant.com с использованием Python.
🔨Требуется: понимание циклов, структур данных, обработки исключений и базовые знания о CSS
селекторах. bs4
, requests
, lxml
библиотеки.
⏱️Сколько времени это займет: ~15–20 минут на чтение и реализацию.
- Что такое поиск Qwant
- Что будет соскабливать
- Предпосылки
- "Процесс"
- Органические результаты
- Результаты рекламы
- "Код"
- Ссылки
- Аутро
Что такое Qwant-поиск
Qwant — это европейская поисковая система, не отслеживающая пользователей для рекламы, расположенная в Париже, с независимой системой индексации, доступная на 26 языках и имеющая более 30 миллионов индивидуальных пользователей в месяц по всему миру.
Что будет очищено
Предпосылки
Извлечение базовых знаний с помощью селекторов CSS
Если вы еще не использовали селекторы CSS
, в моем блоге есть отдельная запись о том, как использовать селекторы CSS
при веб-скрейпинге, в которой рассказывается, что это такое, плюсы и минусы, и почему они важны для веб-скрейпинга. перспектива.
CSS
селекторы объявляют, к какой части разметки применяется стиль, что позволяет извлекать данные из соответствующих тегов и атрибутов.
Отдельная виртуальная среда
Если вы раньше не работали с виртуальной средой, ознакомьтесь с моей специальной записью в блоге Учебное пособие по виртуальной среде Python с использованием Virtualenv и Poetry, чтобы ознакомиться с ней.
Короче говоря, это то, что создает независимый набор установленных библиотек, включая разные версии Python, которые могут сосуществовать друг с другом в одной системе, что предотвращает конфликты библиотек или версий Python.
Установите библиотеки:
pip install requests
pip install lxml
pip install beautifulsoup4
Уменьшить вероятность блокировки
Есть вероятность, что запрос может быть заблокирован. Взгляните на как уменьшить вероятность блокировки во время веб-скрейпинга, есть одиннадцать способов обойти блокировки с большинства веб-сайтов.
Процесс
Если вам не нужно объяснение:
- перейти к разделу полный код,
- попробовать в онлайн-IDE.
Стартовый код как для обычных, так и для рекламных результатов:
from bs4 import BeautifulSoup import requests, lxml, json
headers = { "User-Agent": "Mozilla/5.0 (Linux; Android 10; HD1913) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36 EdgA/46.1.2.5140" }
params = { "q": "minecraft", "t": "web" }
html = requests.get("https://www.qwant.com/", params=params, headers=headers, timeout=20) soup = BeautifulSoup(html.text, "lxml") # further code...
Импортировать библиотеки:
from bs4 import BeautifulSoup
import requests, lxml, json
Добавьтеuser-agent
и параметры запроса в запрос:
headers = { "User-Agent": "Mozilla/5.0 (Linux; Android 10; HD1913) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36 EdgA/46.1.2.5140" }
params = { "q": "minecraft", # search query "t": "web" # qwant query argument for displaying web results }
Создать запрос, добавить timeout
аргумент, создать BeautifulSoup()
объект:
html = requests.get("https://www.qwant.com/", params=params, headers=headers, timeout=20)
soup = BeautifulSoup(html.text, "lxml")
- Параметр
timeout
сообщитrequests
прекратить ожидание ответа через X секунд. BeautifulSoup()
— это то, что извлекает все данные HTML.lxml
— это парсер HTML.
Извлечение органических результатов
def scrape_organic_results():
organic_results_data = []
for index, result in enumerate(soup.select("[data-testid=webResult]"), start=1): title = result.select_one(".WebResult-module__title___MOBFg").text link = result.select_one(".Stack-module__VerticalStack___2NDle.Stack-module__Spacexxs___3wU9G a")["href"] snippet = result.select_one(".Box-module__marginTopxxs___RMB_d").text
try: displayed_link = result.select_one(".WebResult-module__permalink___MJGeh").text favicon = result.select_one(".WebResult-module__iconBox___3DAv5 img")["src"] except: displayed_link = None favicon = None
organic_results_data.append({ "position": index, "title": title, "link": link, "displayed_link": displayed_link, "snippet": snippet, "favicon": favicon })
print(json.dumps(organic_results_data, indent=2))
scrape_oragnic_results()
Создайте временныйlist()
для хранения извлеченных данных:
organic_results_data = []
Повторите и извлеките данные:
for index, result in enumerate(soup.select("[data-testid=webResult]"), start=1): title = result.select_one(".WebResult-module__title___MOBFg").text link = result.select_one(".Stack-module__VerticalStack___2NDle.Stack-module__Spacexxs___3wU9G a")["href"] snippet = result.select_one(".Box-module__marginTopxxs___RMB_d").text
try: displayed_link = result.select_one(".WebResult-module__permalink___MJGeh").text favicon = result.select_one(".WebResult-module__iconBox___3DAv5 img")["src"] except: displayed_link = None favicon = None
Чтобы получить индекс позиции, мы можем использовать функцию enumerate()
, которая добавляет счетчик к итерации и возвращает его и установить start
в 1
, чтобы отсчет начинался с 1, а не с 0.
Для обработки значений None
мы можем использовать блок try/except
, поэтому, если в бэкэнде Qwant ничего нет, мы также установим для него значение None
, в противном случае будет выдано сообщение об отсутствии такого элемента или атрибута.
Добавить извлеченные данные к временному list()
в качестве словаря:
organic_results_data.append({
"position": index,
"title": title,
"link": link,
"displayed_link": displayed_link,
"snippet": snippet,
"favicon": favicon
})
Распечатать данные:
print(json.dumps(organic_results_data, indent=2))
# part of the output: ''' [ { "position": 1, "title": "Minecraft Official Site | Minecraft", "link": "https://www.minecraft.net/", "displayed_link": "minecraft.net", "snippet": "Get all-new items in the Minecraft Master Chief Mash-Up DLC on 12/10, and the Superintendent shirt in Character Creator, free for a limited time! Learn more. Climb high and dig deep. Explore bigger mountains, caves, and biomes along with an increased world height and updated terrain generation in the Caves & Cliffs Update: Part II! Learn more . Play Minecraft games with Game Pass. Get your ...", "favicon": "https://s.qwant.com/fav/m/i/www_minecraft_net.ico" }, ... other results { "position": 10, "title": "Minecraft - download free full version game for PC ...", "link": "https://freegamepick.net/en/minecraft/", "displayed_link": "freegamepick.net", "snippet": "Minecraft Download Game Overview. Minecraft is a game about breaking and placing blocks. It's developed by Mojang. At first, people built structures to protect against nocturnal monsters, but as the game grew players worked together to create wonderful, imaginative things. It can als o be about adventuring with friends or watching the sun rise over a blocky ocean.", "favicon": "https://s.qwant.com/fav/f/r/freegamepick_net.ico" } ] '''
Извлечь результаты рекламы
def scrape_ad_results():
ad_results_data = []
for index, ad_result in enumerate(soup.select("[data-testid=adResult]"), start=1): ad_title = ad_result.select_one(".WebResult-module__title___MOBFg").text ad_link = ad_result.select_one(".Stack-module__VerticalStack___2NDle a")["href"] ad_displayed_link = ad_result.select_one(".WebResult-module__domain___1LJmo").text ad_snippet = ad_result.select_one(".Box-module__marginTopxxs___RMB_d").text ad_favicon = ad_result.select_one(".WebResult-module__iconBox___3DAv5 img")["src"]
ad_results_data.append({ "ad_position": index, "ad_title": ad_title, "ad_link": ad_link, "ad_displayed_link": ad_displayed_link, "ad_snippet": ad_snippet, "ad_favicon": ad_favicon })
print(json.dumps(ad_results_data, indent=2))
scrape_ad_results()
Создайте временныйlist()
для хранения извлеченных данных:
ad_results_data = []
Повторить и извлечь:
for index, ad_result in enumerate(soup.select("[data-testid=adResult]"), start=1):
ad_title = ad_result.select_one(".WebResult-module__title___MOBFg").text
ad_link = ad_result.select_one(".Stack-module__VerticalStack___2NDle a")["href"]
ad_displayed_link = ad_result.select_one(".WebResult-module__domain___1LJmo").text
ad_snippet = ad_result.select_one(".Box-module__marginTopxxs___RMB_d").text
ad_favicon = ad_result.select_one(".WebResult-module__iconBox___3DAv5 img")["src"]
Тот же подход был использован для получения индекса позиции. Единственная разница заключается в другом CSS
селекторе "контейнера" [data-testid=adResult]
, тогда как в органических результатах это [data-testid=webResult]
.
Добавить извлеченные данные во временный файлlist()
в виде словаря:
ad_results_data.append({
"ad_position": index,
"ad_title": ad_title,
"ad_link": ad_link,
"ad_displayed_link": ad_displayed_link,
"ad_snippet": ad_snippet
})
Распечатать данные:
print(json.dumps(ad_results_data, indent=2))
# output: ''' [ { "ad_position": 1, "ad_title": "Watch Movies & TV on Amazon - Download in HD on Amazon Video", "ad_link": "https://www.bing.com/aclick?ld=e8pyYjhclU87kOyQ4ap78CRzVUCUxgK0MGMfKx1YlQe_w7Nbzamra9cSRmPFAtSOVF4MliAqbJNdotR3G-aqHSaMOI0tqV9K0EAFRTemYDKhbqLyjFW93Lsh0mnyySb8oIj6GXADnoePUk-etFDgSvPdZI0xObBo4hesqbOHypYhSGeJ-ZbG1eY0kijv95k0XJ9WKPPA&u=aHR0cHMlM2ElMmYlMmZ3d3cuYW1hem9uLmNvLnVrJTJmcyUyZiUzZmllJTNkVVRGOCUyNmtleXdvcmRzJTNkbWluZWNyYWZ0JTJidGhlJTI2aW5kZXglM2RhcHMlMjZ0YWclM2RoeWRydWtzcG0tMjElMjZyZWYlM2RwZF9zbF8ydmdscmFubWxwX2UlMjZhZGdycGlkJTNkMTE0NDU5MjQzNjk0ODQzOSUyNmh2YWRpZCUzZDcxNTM3MTUwMzgzNDA4JTI2aHZuZXR3JTNkcyUyNmh2cW10JTNkZSUyNmh2Ym10JTNkYmUlMjZodmRldiUzZG0lMjZodmxvY2ludCUzZCUyNmh2bG9jcGh5JTNkMTQxMTcxJTI2aHZ0YXJnaWQlM2Rrd2QtNzE1Mzc2Njc4MjI5NzklM2Fsb2MtMjM1JTI2aHlkYWRjciUzZDU5MTJfMTg4MTc4NQ&rlid=c61aa73b62e916116cbdc687c021190a", "ad_displayed_link": "amazon.co.uk", "ad_snippet": "Download now. Watch anytime on Amazon Video.", "ad_favicon": "https://s.qwant.com/fav/a/m/www_amazon_co_uk.ico" } ] '''
Полный код
from bs4 import BeautifulSoup import requests, lxml, json
headers = { "User-Agent": "Mozilla/5.0 (Linux; Android 10; HD1913) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36 EdgA/46.1.2.5140" }
params = { "q": "minecraft", "t": "web" }
html = requests.get("https://www.qwant.com/", params=params, headers=headers, timeout=20) soup = BeautifulSoup(html.text, "lxml")
def scrape_organic_results():
organic_results_data = []
for index, result in enumerate(soup.select("[data-testid=webResult]"), start=1): title = result.select_one(".WebResult-module__title___MOBFg").text link = result.select_one(".Stack-module__VerticalStack___2NDle.Stack-module__Spacexxs___3wU9G a")["href"] snippet = result.select_one(".Box-module__marginTopxxs___RMB_d").text
try: displayed_link = result.select_one(".WebResult-module__permalink___MJGeh").text favicon = result.select_one(".WebResult-module__iconBox___3DAv5 img")["src"] except: displayed_link = None favicon = None
organic_results_data.append({ "position": index, "title": title, "link": link, "displayed_link": displayed_link, "snippet": snippet, "favicon": favicon })
print(json.dumps(organic_results_data, indent=2))
def scrape_ad_results():
ad_results_data = []
for index, ad_result in enumerate(soup.select("[data-testid=adResult]"), start=1): ad_position = index + 1 ad_title = ad_result.select_one(".WebResult-module__title___MOBFg").text ad_link = ad_result.select_one(".Stack-module__VerticalStack___2NDle a")["href"] ad_displayed_link = ad_result.select_one(".WebResult-module__domain___1LJmo").text ad_snippet = ad_result.select_one(".Box-module__marginTopxxs___RMB_d").text ad_favicon = ad_result.select_one(".WebResult-module__iconBox___3DAv5 img")["src"]
ad_results_data.append({ "ad_position": index, "ad_title": ad_title, "ad_link": ad_link, "ad_displayed_link": ad_displayed_link, "ad_snippet": ad_snippet, "ad_favicon": ad_favicon })
print(json.dumps(ad_results_data, indent=2))
Ссылки
Outro
Если у вас есть чем поделиться, какие-либо вопросы или предложения по этому сообщению в блоге, не стесняйтесь обращаться через Twitter по адресу @dimitryzub или @serp_api.
С уважением,
Дмитрий, и остальная часть команды SerpApi.
Присоединяйтесь к нам на Reddit | Твиттер | "YouTube"
Добавьте Запрос функции💫 или Ошибку🐞
Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Получите эксклюзивный доступ к возможностям написания и советам в нашем сообществе Discord.