Как извлечь органические результаты видео из Brave Search с помощью Python
Этот пост в блоге покажет вам, как извлечь результаты видео Brave из органических результатов и вкладки видео.
- "Вступление"
- Что будет соскабливать
- Что такое смелый поиск
- Полный код
- "Подготовка"
- Пояснение кода
- Очистить органические видео
- Очистить вкладку видео
- Ссылки
вступление
В настоящее время у нас нет API, поддерживающего извлечение данных из Brave Search.
Этот пост в блоге должен показать вам, как вы можете сделать это самостоятельно с помощью предоставленного ниже решения DIY, пока мы работаем над выпуском нашего надлежащего API.
Решение можно использовать для личного использования, так как оно не включает Юридический щит США, который мы предлагаем для наших платных производственных и выше планов, и имеет свои ограничения, такие как необходимость обхода блоков, например, CAPTCHA.
Вы можете проверить нашу общедоступную дорожную карту, чтобы отслеживать прогресс для этого API: [Новый API] Brave Videos
Что будет очищено
📌Примечание: Иногда в органической выдаче может отсутствовать видео. Этот пост в блоге получает видео из органических результатов и вкладки видео.
Что такое смелый поиск
В предыдущем сообщении в блоге Brave ранее описывалось что такое Brave search. Во избежание дублирования контента эта информация не упоминается в этом сообщении блога.
Полный код
Если вам не нужны объяснения, посмотрите полный пример кода в онлайн-IDE.
from bs4 import BeautifulSoup import requests, lxml, json, re
# https://docs.python-requests.org/en/master/user/quickstart/#passing-parameters-in-urls params = { 'q': 'dune 2021', # query 'source': 'web', # source 'tf': 'at', # publish time (at - any time, pd - past day, pw - past week, pm - past month) 'length': 'all', # duration (short, medium, long) 'resolution': 'all' # resolution (1080p, 720p, 480p, 360p) }
# https://docs.python-requests.org/en/master/user/quickstart/#custom-headers headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36' }
def scrape_organic_videos(): html = requests.get('https://search.brave.com/search', headers=headers, params=params) soup = BeautifulSoup(html.text, 'lxml')
data = []
for result in soup.select('#video-carousel .card'): title = result.select_one('.title').get_text() link = result.get('href') source = result.select_one('.anchor').get_text().strip() date = result.select_one('.text-xs').get_text().strip() favicon = result.select_one('.favicon').get('src') # https://regex101.com/r/7OA1FS/1 thumbnail = re.search(r"background-image:\surl\('(.*)'\)", result.select_one('.img-bg').get('style')).group(1)
video_duration = ( result.select_one('.duration').get_text() if result.select_one('.duration') else None )
data.append({ 'title': title, 'link': link, 'source': source, 'date': date, 'favicon': favicon, 'thumbnail': thumbnail, 'video_duration': video_duration })
return data
def scrape_tab_videos(): html = requests.get('https://search.brave.com/videos', headers=headers, params=params) soup = BeautifulSoup(html.text, 'lxml')
data = []
for result in soup.select('.card'): title = result.select_one('.title').get_text() link = result.select_one('a').get('href') source = result.select_one('.center-horizontally .ellipsis').get_text().strip() date = result.select_one('#results span').get_text().strip() favicon = result.select_one('.favicon').get('src') # https://regex101.com/r/7OA1FS/1 thumbnail = re.search(r"background-image:\surl\('(.*)'\)", result.select_one('.img-bg').get('style')).group(1)
creator = ( result.select_one('.creator').get_text().strip() if result.select_one('.creator') else None )
views = ( result.select_one('.stat').get_text().strip() if result.select_one('.stat') else None )
video_duration = ( result.select_one('.duration').get_text() if result.select_one('.duration') else None )
data.append({ 'title': title, 'link': link, 'source': source, 'creator': creator, 'date': date, 'views': views, 'favicon': favicon, 'thumbnail': thumbnail, 'video_duration': video_duration, })
return data
if __name__ == "__main__": # brave_organic_videos = scrape_organic_videos() # print(json.dumps(brave_organic_videos, indent=2, ensure_ascii=False))
brave_tab_videos = scrape_tab_videos() print(json.dumps(brave_tab_videos, indent=2, ensure_ascii=False))
Подготовка
Установите библиотеки:
pip install requests lxml beautifulsoup4
Извлечение базовых знаний с помощью селекторов CSS
Селекторы CSS объявляют, к какой части разметки применяется стиль, что позволяет извлекать данные из соответствующих тегов и атрибутов.
Если вы еще не парились с селекторами CSS, в моем блоге есть отдельная запись о том, как использовать селекторы CSS при парсинге веб-страниц, в которой рассказывается, что это такое, плюсы и минусы, и почему они важны для парсинга веб-страниц. перспектива.
Уменьшить вероятность блокировки
Убедитесь, что вы используете заголовки запроса user-agent
, чтобы действовать как настоящий визит пользователя. Потому что по умолчанию requests
user-agent
равно python-requests
, и веб-сайты понимают, что это, скорее всего, скрипт, который отправляет запрос. Проверь, какой у тебя user-agent
.
Есть как уменьшить вероятность блокировки при парсинге поста в блоге, который может познакомить вас с базовыми и более продвинутыми подходами.
Код Пояснение
Импортировать библиотеки:
from bs4 import BeautifulSoup
import requests, lxml, json, re
BeautifulSoup
для сбора информации с веб-страниц. Он находится поверх синтаксического анализатора HTML или XML, предоставляя идиомы Pythonic для итерации, поиска и изменения дерева синтаксического анализа.requests
сделать запрос на сайт.lxml
для быстрой обработки документов XML/HTML.json
для преобразования извлеченных данных в объект JSON.re
для извлечения частей данных с помощью регулярных выражений.
Создайте параметры URL и заголовки запроса:
# https://docs.python-requests.org/en/master/user/quickstart/#passing-parameters-in-urls params = { 'q': 'dune 2021', # query 'source': 'web', # source 'tf': 'at', # publish time (at - any time, pd - past day, pw - past week, pm - past month) 'length': 'all', # duration (short, medium, long) 'resolution': 'all' # resolution (1080p, 720p, 480p, 360p) }
# https://docs.python-requests.org/en/master/user/quickstart/#custom-headers headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36' }
params
более красивый способ передачи параметров URL в запрос.user-agent
действовать как настоящий пользовательский запрос от браузера, передавая его в заголовки запроса. По умолчаниюrequests
user-agent — этоpython-reqeusts
, чтобы веб-сайты могли понять, что это бот или скрипт, и заблокировать запрос к веб-сайту. Проверь, какой у тебяuser-agent
.
Собрать органические видео
Эта функция очищает все данные органических видео для URL-адреса https://search.brave.com/search
и возвращает список со всеми результатами.
Вам нужно сделать запрос, передать созданные параметры запроса и заголовки. Запрос возвращает HTML в BeautifulSoup:
html = requests.get('https://search.brave.com/search', headers=headers, params=params)
soup = BeautifulSoup(html.text, 'lxml')
timeout=30
перестать ждать ответа через 30 секунд.BeautifulSoup()
где возвращенные данные HTML будут обработаныbs4
.
Создайте список data
для хранения всех видео:
data = []
Чтобы извлечь нужные данные, нужно найти селектор, где они находятся. В нашем случае это селектор #video-carousel .card
, в котором собраны все органические видео. Вам нужно повторить каждое видео в цикле:
for result in soup.select('#video-carousel .card'):
# data extraction will be here
Чтобы извлечь данные, вам нужно найти соответствующие селекторы. SelectorGadget использовался для захвата селекторов CSS. Я хочу продемонстрировать, как работает процесс выбора селектора:
После того, как селекторы найдены, нам нужно получить соответствующий текст или значение атрибута. Хочу обратить ваше внимание на то, что thumbnail
добывается другим способом.
Нужная ссылка на изображение скрыта внутри атрибута style
. Чтобы извлечь эту ссылку, вам нужно сделать много операций над строкой. Вместо этого вы можете использовать регулярное выражение для извлечения необходимых данных:
title = result.select_one('.title').get_text() link = result.get('href') source = result.select_one('.anchor').get_text().strip() date = result.select_one('.text-xs').get_text().strip() favicon = result.select_one('.favicon').get('src') # https://regex101.com/r/7OA1FS/1 thumbnail = re.search(r"background-image:\surl\('(.*)'\)", result.select_one('.img-bg').get('style')).group(1)
video_duration = ( result.select_one('.duration').get_text() if result.select_one('.duration') else None )
📌Примечание: при извлечении video_duration
используется троичное выражение, которое обрабатывает значения этих данных, если таковые имеются.
select_one()
/select()
, чтобы запустить селектор CSS для проанализированного документа и вернуть все соответствующие элементы.get_text()
для получения текстовых данных от узла.get(<attribute>)
чтобы получить данные атрибутов от узла.strip()
чтобы вернуть копию строки с удаленными начальными и конечными символами.search()
для поиска шаблона в строке и возврата соответствующего объекта соответствия.group()
для извлечения найденного элемента из объекта сопоставления.
После извлечения данных из элемента они добавляются в список data
:
data.append({
'title': title,
'link': link,
'source': source,
'date': date,
'favicon': favicon,
'thumbnail': thumbnail,
'video_duration': video_duration
})
Полная функция очистки органических видео будет выглядеть так:
def scrape_organic_videos(): html = requests.get('https://search.brave.com/search', headers=headers, params=params) soup = BeautifulSoup(html.text, 'lxml')
data = []
for result in soup.select('#video-carousel .card'): title = result.select_one('.title').get_text() link = result.get('href') source = result.select_one('.anchor').get_text().strip() date = result.select_one('.text-xs').get_text().strip() favicon = result.select_one('.favicon').get('src') # https://regex101.com/r/7OA1FS/1 thumbnail = re.search(r"background-image:\surl\('(.*)'\)", result.select_one('.img-bg').get('style')).group(1)
video_duration = ( result.select_one('.duration').get_text() if result.select_one('.duration') else None )
data.append({ 'title': title, 'link': link, 'source': source, 'date': date, 'favicon': favicon, 'thumbnail': thumbnail, 'video_duration': video_duration })
return data
Выход:
[
{
"title": "Dune | Official Main Trailer - YouTube",
"link": "https://www.youtube.com/watch?v=8g18jFHCLXk",
"source": "youtube.com",
"date": "July 22, 2021",
"favicon": "https://imgs.search.brave.com/Ux4Hee4evZhvjuTKwtapBycOGjGDci2Gvn2pbSzvbC0/rs:fit:32:32:1/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvOTkyZTZiMWU3/YzU3Nzc5YjExYzUy/N2VhZTIxOWNlYjM5/ZGVjN2MyZDY4Nzdh/ZDYzMTYxNmI5N2Rk/Y2Q3N2FkNy93d3cu/eW91dHViZS5jb20v",
"thumbnail": "https://imgs.search.brave.com/E6_Wv3qlA5iqnRkLZILt8tq-lLKCHVwJESItayT5jro/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9pLnl0/aW1nLmNvbS92aS84/ZzE4akZIQ0xYay9t/YXhyZXNkZWZhdWx0/LmpwZw",
"video_duration": "03:28"
},
{
"title": "Dune Official Trailer - YouTube",
"link": "https://www.youtube.com/watch?v=n9xhJrPXop4",
"source": "youtube.com",
"date": "September 9, 2020",
"favicon": "https://imgs.search.brave.com/Ux4Hee4evZhvjuTKwtapBycOGjGDci2Gvn2pbSzvbC0/rs:fit:32:32:1/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvOTkyZTZiMWU3/YzU3Nzc5YjExYzUy/N2VhZTIxOWNlYjM5/ZGVjN2MyZDY4Nzdh/ZDYzMTYxNmI5N2Rk/Y2Q3N2FkNy93d3cu/eW91dHViZS5jb20v",
"thumbnail": "https://imgs.search.brave.com/uNV6ho7lr6Z-67_BgPPOp56rj-aVny1loaiYzGyLwQk/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9pLnl0/aW1nLmNvbS92aS9u/OXhoSnJQWG9wNC9t/YXhyZXNkZWZhdWx0/LmpwZw",
"video_duration": "03:05"
},
{
"title": "DUNE – FINAL TRAILER - YouTube",
"link": "https://www.youtube.com/watch?v=w0HgHet0sxg",
"source": "youtube.com",
"date": "October 7, 2021",
"favicon": "https://imgs.search.brave.com/Ux4Hee4evZhvjuTKwtapBycOGjGDci2Gvn2pbSzvbC0/rs:fit:32:32:1/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvOTkyZTZiMWU3/YzU3Nzc5YjExYzUy/N2VhZTIxOWNlYjM5/ZGVjN2MyZDY4Nzdh/ZDYzMTYxNmI5N2Rk/Y2Q3N2FkNy93d3cu/eW91dHViZS5jb20v",
"thumbnail": "https://imgs.search.brave.com/-irGOLELOj8B0YDVJU5dHgpWsd8nSx2l3yrVARUlv0E/rs:fit:200:200:1/g:ce/aHR0cHM6Ly9pLnl0/aW1nLmNvbS92aS93/MEhnSGV0MHN4Zy9t/YXhyZXNkZWZhdWx0/LmpwZw",
"video_duration": "02:29"
},
... other videos
]
Очистка видео на вкладке
Эта функция очищает все данные видео на вкладке для URL-адреса https://search.brave.com/videos
и возвращает список со всеми результатами.
Вам нужно сделать запрос, передать созданные параметры запроса и заголовки. Запрос возвращает HTML в BeautifulSoup:
html = requests.get('https://search.brave.com/videos', headers=headers, params=params)
soup = BeautifulSoup(html.text, 'lxml')
Создайте список data
для хранения всех видео:
data = []
Чтобы получить данные из всех видео на странице, вам нужно найти селектор элементов .card
. Вам нужно повторить каждый элемент в цикле:
for result in soup.select('.card'):
# data extraction will be here
На этой странице соответствующие селекторы отличаются. Так что эта функция также использовала SelectorGadget для захвата селекторов CSS. Я хочу продемонстрировать, как работает процесс выбора селектора:
Отличие извлечения данных в этой функции в том, что здесь можно получить creator
и views
:
title = result.select_one('.title').get_text() link = result.select_one('a').get('href') source = result.select_one('.center-horizontally .ellipsis').get_text().strip() date = result.select_one('#results span').get_text().strip() favicon = result.select_one('.favicon').get('src') # https://regex101.com/r/7OA1FS/1 thumbnail = re.search(r"background-image:\surl\('(.*)'\)", result.select_one('.img-bg').get('style')).group(1)
creator = ( result.select_one('.creator').get_text().strip() if result.select_one('.creator') else None )
views = ( result.select_one('.stat').get_text().strip() if result.select_one('.stat') else None )
video_duration = ( result.select_one('.duration').get_text() if result.select_one('.duration') else None )
📌Примечание: при извлечении creator
, views
и video_duration
используется троичное выражение, которое обрабатывает значения этих данных, если они доступны.
После извлечения данных из элемента они добавляются в список data
:
data.append({
'title': title,
'link': link,
'source': source,
'creator': creator,
'date': date,
'views': views,
'favicon': favicon,
'thumbnail': thumbnail,
'video_duration': video_duration,
})
Полная функция очистки видео с вкладок будет выглядеть так:
def scrape_tab_videos(): html = requests.get('https://search.brave.com/videos', headers=headers, params=params) soup = BeautifulSoup(html.text, 'lxml')
data = []
for result in soup.select('.card'): title = result.select_one('.title').get_text() link = result.select_one('a').get('href') source = result.select_one('.center-horizontally .ellipsis').get_text().strip() date = result.select_one('#results span').get_text().strip() favicon = result.select_one('.favicon').get('src') # https://regex101.com/r/7OA1FS/1 thumbnail = re.search(r"background-image:\surl\('(.*)'\)", result.select_one('.img-bg').get('style')).group(1)
creator = ( result.select_one('.creator').get_text().strip() if result.select_one('.creator') else None )
views = ( result.select_one('.stat').get_text().strip() if result.select_one('.stat') else None )
video_duration = ( result.select_one('.duration').get_text() if result.select_one('.duration') else None )
data.append({ 'title': title, 'link': link, 'source': source, 'creator': creator, 'date': date, 'views': views, 'favicon': favicon, 'thumbnail': thumbnail, 'video_duration': video_duration, })
return data
Выход:
[
{
"title": "Dune (2021)",
"link": "https://www.imdb.com/title/tt1160419/",
"source": "IMDB",
"creator": null,
"date": "28 Jan, 2010",
"views": null,
"favicon": "https://imgs.search.brave.com/_XzIkQDCEJ7aNlT3HlNUHBRcj5nQ9R4TiU4cHpSn7BY/rs:fit:32:32:1/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvZmU3MjU1MmUz/MDhkYjY0OGFlYzY3/ZDVlMmQ4NWZjZDhh/NzZhOGZlZjNjNGE5/M2M0OWI1Y2M2ZjQy/MWE5ZDc3OC93d3cu/aW1kYi5jb20v",
"thumbnail": "https://imgs.search.brave.com/zHiJ3yZ-f7a99EkHYp8nB2BD0XvWk5fKq-dcukd5Jro/rs:fit:235:225:1/g:ce/aHR0cHM6Ly90c2U0/Lm1tLmJpbmcubmV0/L3RoP2lkPU9WUC43/WUM5TEhVTGxFaEFm/VGNVNzZqZGRBRmVJ/SSZwaWQ9QXBp",
"video_duration": "03:05"
},
{
"title": "Dune Review (2021)",
"link": "https://www.youtube.com/watch?v=DqquKCvOxwA",
"source": "YouTube",
"creator": "IGN",
"date": "03 Sep, 2021",
"views": "568.14K",
"favicon": "https://imgs.search.brave.com/Ux4Hee4evZhvjuTKwtapBycOGjGDci2Gvn2pbSzvbC0/rs:fit:32:32:1/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvOTkyZTZiMWU3/YzU3Nzc5YjExYzUy/N2VhZTIxOWNlYjM5/ZGVjN2MyZDY4Nzdh/ZDYzMTYxNmI5N2Rk/Y2Q3N2FkNy93d3cu/eW91dHViZS5jb20v",
"thumbnail": "https://imgs.search.brave.com/Eru5tXsCCm42JOqGxc3XsNe8RPs0_Fk1Bs0AVvmpDQE/rs:fit:640:225:1/g:ce/aHR0cHM6Ly90c2Ux/Lm1tLmJpbmcubmV0/L3RoP2lkPU9WUC5q/TU5XYmtTdGFHalJY/X0JSQm1mUV9RSGdG/byZwaWQ9QXBp",
"video_duration": "04:31"
},
{
"title": "DUNE Trailer 2 (2021)",
"link": "https://www.youtube.com/watch?v=LG7QhzmavZg",
"source": "YouTube",
"creator": "KinoCheck.com",
"date": "22 Jul, 2021",
"views": "485.53K",
"favicon": "https://imgs.search.brave.com/Ux4Hee4evZhvjuTKwtapBycOGjGDci2Gvn2pbSzvbC0/rs:fit:32:32:1/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvOTkyZTZiMWU3/YzU3Nzc5YjExYzUy/N2VhZTIxOWNlYjM5/ZGVjN2MyZDY4Nzdh/ZDYzMTYxNmI5N2Rk/Y2Q3N2FkNy93d3cu/eW91dHViZS5jb20v",
"thumbnail": "https://imgs.search.brave.com/XHCBNZHpAHNxvYqWYgfhYKKinSHXdYjI3e5HtsgVjcg/rs:fit:640:225:1/g:ce/aHR0cHM6Ly90c2Uy/Lm1tLmJpbmcubmV0/L3RoP2lkPU9WUC5q/VXZ2aE1Md1hfWUtM/OHZsU0l3SFJRSGdG/byZwaWQ9QXBp",
"video_duration": "03:37"
},
... other videos
]
Ссылки
Присоединяйтесь к нам в Твиттере | "YouTube"
Добавьте Запрос функции💫 или Ошибку🐞
Первоначально опубликовано на https://serpapi.com 1 ноября 2021 г.
Больше контента на plainenglish.io