Очистите видеоролики Brave с помощью Python

вступление

В настоящее время у нас нет API, поддерживающего извлечение данных из Brave Search.

Этот пост в блоге должен показать вам, как вы можете сделать это самостоятельно с помощью предоставленного ниже решения DIY, пока мы работаем над выпуском нашего надлежащего API.

Решение можно использовать для личного использования, так как оно не включает Юридический щит США, который мы предлагаем для наших платных производственных и выше планов, и имеет свои ограничения, такие как необходимость обхода блоков, например, CAPTCHA.

Вы можете проверить нашу общедоступную дорожную карту, чтобы отслеживать прогресс для этого API:

[Новый API] Храбрый поиск

Что будет очищено

📌Примечание: Иногда в органической выдаче может отсутствовать видео. Этот пост в блоге получает видео из органических результатов и вкладки видео.

Что такое смелый поиск

В предыдущем сообщении в блоге 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'
}

Собрать органические видео

Эта функция очищает все данные органических видео для 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
]

Ссылки

Первоначально опубликовано на SerpApi: https://serpapi.com/blog/scrape-organic-video-results-from-brave-search-with-python/

Присоединяйтесь к нам в Твиттере | "YouTube"

Добавьте Запрос функции💫 или Ошибку🐞