СТАТЬЯ

Парсим ресурсы Codeby на языке Python

MySystem32
MySystem32 Newbie · 59 сообщений
Подписаться
7,3 тыс.
[ обложка статьи ]
Режим чтения
Стоит сразу оговориться: разобранный ниже метод с requests и BeautifulSoup отлично работает для статичных страниц, где нужные данные уже лежат в HTML-коде ответа сервера. Но если ресурс подгружает контент через JavaScript (например, динамическую пагинацию, ленивую загрузку блоков или данные, которые появляются только после действий пользователя), такой парсер просто не увидит нужные элементы — soup.find_all вернёт пустоту или неполные данные. В таких случаях на помощь приходят инструменты вроде Selenium или Playwright, эмулирующие полноценный браузер и дожидающиеся отрисовки страницы. В нашем случае страница ресурсов Codeby отдаёт готовую разметку сразу, поэтому классической связки requests + bs4 будет достаточно — но держите в голове этот нюанс, если решите адаптировать скрипт под другие сайты.



i



🧰 Что такое парсинг?
Парсинг (Parsing) – это принятое в информатике определение синтаксического анализа. Для этого создается математическая модель сравнения лексем с формальной грамматикой, описанная одним из языков программирования. Например, PHP, Perl, Ruby, Python.
Когда человек читает, то, с точки зрения науки филологии, он совершает синтаксический анализ, сравнивая увиденные на бумаге слова (лексемы) с теми, что есть в его словарном запасе (формальной грамматикой).
Программа (скрипт), дающая возможность компьютеру «читать» – сравнивать предложенные слова с имеющимися во Всемирной сети, называется парсером. Сфера применения таких программ очень широка, но все они работают практически по одному алгоритму.
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Источник: Парсинг - что это такое, зачем используется
👋 План действий
Сегодня я вам расскажу как правильно парсить данные с помощью языка Python, и будем мы парсить именно codeby ресурсы.
Если зайти на страницу ресурсов:

Screenshot 2022-06-13 at 15-38-34 Брендинг codeby.png

то мы увидим обычные ресурсы, которые видит любой пользователь Codeby (парсинг контента для авторизованных пользователей я сделаю позже), а сейчас мы должны спарсить эти ресурсы, что именно мы будем получать с сайта?


Screenshot 2022-06-13 at 15-40-24 Брендинг codeby.png

Мы должны спарсить этот блок, включая: название ресурса, автор ресурса, дата создания ресурса и так же описание ресурса ("Исходник в векторе, png и jpg"), ну и конечно же после этого мы должны всё это экспортировать в CSV файле.
Надеюсь вы поняли, приступим к коду.


✴️ Пишем парсер
Перед написанием кода нужно установить 3 библиотеки - requests, csv, bs4

установка библиотеки requests
pip install requests

установка библиотеки BeautifulSoup(bs4)
pip install bs4

установка библиотеки Csv
pip install csv

●︎ requests - нужен для запросов, обращение к сайту(codeby.net);
●︎ beautifulSoup - нужен для парсинга, а именно для нас парсинг блоков;
●︎ csv - нужен для порядка данных, таблица.

После установки библиотек создадим несколько библиотек данных Codeby:
Python:
import requests
from bs4 import BeautifulSoup
import csv

CSV = 'resources.csv' # создания csv файла после запуска парсинга (можете указать путь)
HOST = "https://codeby.net/" # хост
URL = "https://codeby.net/resources/categories/brending-codeby.11/" # страница где мы именно будем парсить\
pages = requests.get(URL) # передаем наш URL ссылку к pages'y

первые три строчки для импортирования, переменная CSV это путь создания csv файла (таблица), в нашем случае он создастся в текущем каталоге, где находится python файл;
переменная HOST хранит ссылку на сайт, в нашем случае codeby;
переменная URL хранит ссылку страницы где мы будем парсить;
переменная pages хранит тот самый URL в качестве requests, без этого у вас не получится подключиться к этой странице.


После того как мы это сделали, нам нужны заголовки, а точнее юзер-агент и accept, их указывать обязательно не нужно, но без них некоторые сайты блокируют ваш IP, так что в случае такой ситуации рекомендуется это сделать.

Нам нужны User-agent и Accept, где их достать? Заходим на сайт где ресурсы кодебай (не приватные), дальше открываем код элемента, и нажимаем на Netwrok, не закрывая окна обновляем страницу, здесь у нас появятся вот эти фильтры:
image(1).png


где указано стрелочками нажимаем, и дальше откроется окошко с данными, но нам нужны именно User-Agent и Accept:
image.png


сразу копируем.

А теперь нам надо эти данные впихнуть в словаре, для этого в питоне нужно сделать словарь:
Python:
HEADERS = {

    "accept": "ext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0"
}

вот и всё, словарь заполнен, переходим к функциям.


1️⃣ Создаем функцию get_html()

Данная функция предназначена для запроса к сайту, использовании заголовков (HEADERS) и параметров, давайте напишем эту функцию:
Python:
# подключение к странице

def get_html(url, params=''):
    r = requests.get(url, headers=HEADERS, params=params)
    return r

get_html принимает два аргумента url, params. Аргумент url принимает саму ссылку. А вот params уже не так важен. Он нужен, если на сайте будут какие-то параметры, типа: codeby.net...?page. Так как на странице ресурсов отсутствуют такие параметры, то аргумент вы можете просто оставить пустым. В переменной r уже происходит GET-запрос к сайту с помощью библиотеки requests, где мы передаем headers, url и params. Затем возвращаем ответ c помощью return.


2️⃣ Создаем функцию get_content()

Вот и дошли до функции, которая будет отвечать за парсинг. Давайте её напишем:
Python:
# полученные html элементы: парсим с bs4
def get_content(html):
    soup = BeautifulSoup(pages.text, 'html.parser')
    items = soup.find_all("div", class_="structItem")
    resources = [] # место где добавляются ресурсы
Функция get_content принимает аргумент html. Затем создаётся переменная soup, которая необходима для сбора данных со страницы. Переменная items хранит весь блок ресурса (который оставил выше), он хранится в div элементе а его класс structItem. И как же это получить? Всё просто, открываем код элемента, выделяем блок и видим данные:

image(2).png

Все блоки имеют div элементы, а так же класс StructItem (скопировать весь класс необязательно). Теперь у нас будет доступ ко всем блокам.

В списке resources уже будут внутренние блоки, а именно: название ресурса, дата создания ресурса, автор ресурса и описание, для этого сделаем небольшой цикл for:
Python:
# цикл: перебираем все данные ресурса включая:(Название ресурса, автор, дата создание)
    for item in items:
        resources.append(
            {

                "title":item.find("div", class_="structItem-title").get_text(), # название ресурса
                "author": item.find("a", class_="username").get_text(), # автор ресурса
                "time": item.find("time", class_="u-dt").get_text(), # дата создание ресурса
                "desc": item.find("div", class_="structItem-resourceTagLine").get_text() # описание ресурса
            }

        )

    return resources

Здесь создаем цикл, который перебирает и добавляет все данные уже в список resources с помощью функции append():
image_code.png

Похожие блоки включают в себя время создания ресурса, его автора и т.п. Я думаю, что сделать это будет не так уж и сложно.

Вот и всё, мы закончили с парсингом (наконец-то), а теперь сделаем функцию, которая всё это сохранит в CSV-файл,

3️⃣Создаем функцию save_documents_csv()

Эта функция, которая будет сохранять все наши данные в CSV-файл. Лет'с гоу:
Python:
def save_documents_csv(items, path):
    with open(path, "w", newline='') as file:
        writer = csv.writer(file, delimiter=";")
        writer.writerow(['Название ресурсов', "Автор ресурсов", "Дата создание ресурсов", "Описание"])
        resources = []

        for item in items:
            writer.writerow([item['title'], item["author"], item["time"], item["desc"]])

Делаем режим для записи файла (w - write), затем с помощью writerow создаем блоки, где каждый блок будет иметь соответствующие данные. Например, в ключе title хранится значение об авторе ресурса.


4️⃣Создаем функцию parser()

Это последняя функция, которая нужна для запуска парсинга, вывода и сохранении в csv файле)
Код функции:

Python:
def parser():
    html = get_html(URL)
    if html.status_code == 200:
        resource = []
        resource.extend(get_content(html.text))
        save_documents_csv(resource, CSV)
    #print(get_content(html))
    #save_documents_csv(CSV)
parser()

Переменная html хранит исходный код страницы. С помощью условия if html.status_code == 200: мы проверяем, что статус ответа от сервера равен 200(успешное подключение), то у нас запустится парсинг. Функция save_documents_csv сохранит эти данные в CSV-файле.
Вот и всё!

📓Весь код

Python:
import requests # нужен запросы, обращаться сайт, статус и т.п
from bs4 import BeautifulSoup # парсинг, собрирать данные и многое другое
import csv # таблица данных, лучше чем в терминале))


# Resources [https://codeby.net/resources/categories/brending-codeby.11/]
# Domain [https://codeby.net/]
# Block Resource(test): DIV structItem structItem--resource is-prefix2  js-inlineModContainer js-resourceListItem-896
# All block resources: structItem-cell structItem-cell--icon structItem-cell--iconExpanded

CSV = 'resources.csv'
HOST = "https://codeby.net/"
URL = "https://codeby.net/resources/categories/brending-codeby.11/"
pages = requests.get(URL)
# User-Agent Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0
# ext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
HEADERS = {

    "accept": "ext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0"
}

# подключение к странице
def get_html(url, params=''):
    r = requests.get(url, headers=HEADERS, params=params)
    return r

# полученные html элементы: парсим с bs4
def get_content(html):
    soup = BeautifulSoup(pages.text, 'html.parser')
    items = soup.find_all("div", class_="structItem")
    resources = [] # место где добавляются ресурсы


# цикл: перебираем все данные ресурса включая:(Название ресурса, автор, дата создание)
    for item in items:
        resources.append(
            {

                "title":item.find("div", class_="structItem-title").get_text(), # название ресурса
                "author": item.find("a", class_="username").get_text(), # автор ресурса
                "time": item.find("time", class_="u-dt").get_text(), # дата создание ресурса
                "desc": item.find("div", class_="structItem-resourceTagLine").get_text() # описание ресурса
            }

        )

    return resources


def save_documents_csv(items, path):
    with open(path, "w", newline='') as file:
        writer = csv.writer(file, delimiter=";")
        writer.writerow(['Название ресурсов', "Автор ресурсов", "Дата создание ресурсов", "Описание"])
        resources = []

        for item in items:
            writer.writerow([item['title'], item["author"], item["time"], item["desc"]])

def parser():
    html = get_html(URL)
    if html.status_code == 200:
        resource = []
        resource.extend(get_content(html.text))
        save_documents_csv(resource, CSV)
    #print(get_content(html))
    #save_documents_csv(CSV)
parser()


📑Результат работы парсинга:
Screenshot_2022-06-13_at_00-42-39_CSV_Viewer_Online.png

Результат кода парсинга в CSV формате. Всё успешно работает.


📂 Важные ссылки
Документация по библиотеке requests - Requests Documentation
Документация по библиотеке BeautifulSoup - BeautifulSoup Documentation

Уроки по библиотеке csv - Python for Beginners: CSV Library

Нашли ошибку в тексте или коде? Срочно сообщите!
Полезно · 6

Комментарии

11
Использовать api не судьба?
 
  • Нравится
Реакции: MySystem32
1
Даже не слыхал про это))) (в плане использовании)
прочитаю как нибудь про апи
Я так понял, что изучаешь тему и заодно документируешь, чтобы лучше отложилось в памяти. Молодец) Желаю успехов в дальнейшем развитии)
 
  • Нравится
Реакции: MLNK и MySystem32
2
Нам нужны User-agent и Accept, где их достать?
Гораздо проще воспользоваться готовым модулем)
fake-useragent

Ну или выбрать любой другой похожий
Search results

Search results


нная функция предназначена для запроса к сайту, использовании заголовков (HEADERS) и параметров, давайте напишем эту функцию:
А зачем нужна переменная r?

Раз уж вы стали изучать язык python, неплохо было бы ознакомиться со стандартами написания кода, в том числе и PEP8
Добавьте в своём редакторе кода настройку, которая будет подсвечивать недочёты. В том же pycharm она работает из коробки и выдаёт вот такое полотно)
1655211768924.png

Неплохо было бы добавить аннотирование переменных и функций, документ строки с описанием и точку входа для более понятного внешнего вида.


Попробуйте добавить к вашей программе какой-нибудь графический интерфейс и поддержку прокси - будет выглядеть ещё лучше)

Успехов!
 
  • Нравится
Реакции: dmitriy_nik, Polyglot, OldGuard и ещё 2
5
Огромное спасибо вам! П
Гораздо проще воспользоваться готовым модулем)
fake-useragent

Огромное спасибо за ваш теплый ответ. Про fake_useragent я вообще не знал, теперь буду знать спасибо
А зачем нужна переменная r?
Переменная r это сам рекуист который можно посмотреть статус состояние подключение, вывод, ну и многое другое

Раз уж вы стали изучать язык python, неплохо было бы ознакомиться со стандартами написания кода, в том числе и PEP8
Добавьте в своём редакторе кода настройку, которая будет подсвечивать недочёты. В том же pycharm она работает из коробки и выдаёт вот такое полотно)
1655211768924.png 1655211768924.png
очень много ворнингов согласен))) хм, наверное в 3.10 версии PEP изменился, надо сделать код свежим, в коментах оставлю

Попробуйте добавить к вашей программе какой-нибудь графический интерфейс и поддержку прокси - будет выглядеть ещё лучше)
сделать на GUI это было бы вообще кайф, что касается прокси, вот знаешь я очень много пытался получать их, бесплатные прокси найдешь в интернете но они как то не действует , питон говорит что они не правильные..((
а покупать прокси не так уж и хочется..

Спасибо тебе за ответ, для меня это ЧеСтЬ )))
 
Друзья, выше код из статьи я изменил, оказывается в нашем коде есть 20+- Warning'ов который показывает Pycharm, следуя по инструкции PEP8 я убрал эти ворнинги теперь нет никаких проблемов.
Python:
import requests  # нужен запросы, обращаться сайт, статус и т.п
from bs4 import BeautifulSoup  # парсинг, собирать данные и многое другое
import csv  # таблица данных

# CSV, HOST, URL & pages
CSV = 'resources.csv'
HOST = "https://codeby.net/"
URL = "https://codeby.net/resources/categories/brending-codeby.11/"
pages = requests.get(URL)

# Словарь с данными
HEADERS = {

    "accept": "ext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0"
}


def get_html(url, params=""):

    r = requests.get(url, headers=HEADERS, params=params)
    return r


def get_content():
    soup = BeautifulSoup(pages.text, 'html.parser')
    items = soup.find_all("div", class_="structItem")
    resources = []

# цикл: перебираем все данные ресурса включая:(Название ресурса, автор, дата создание)
    for item in items:
        resources.append(
            {

                "title": item.find("div", class_="structItem-title").get_text(),  # название ресурса
                "author": item.find("a", class_="username").get_text(),  # автор ресурса
                "time": item.find("time", class_="u-dt").get_text(),  # дата создание ресурса
                "desc": item.find("div", class_="structItem-resourceTagLine").get_text()  # описание ресурса
            }

        )

    return resources


# функция который сохраняет данные в CSV
def save_documents_csv(items, path):
    with open(path, "w", newline='') as file:
        writer = csv.writer(file, delimiter=";")
        writer.writerow(['Название ресурсов', "Автор ресурсов", "Дата создание ресурсов", "Описание"])

        for item in items:
            writer.writerow([item['title'], item["author"], item["time"], item["desc"]])


# Run
def parser():
    html = get_html(URL)
    if html.status_code == 200:
        resource = []
        resource.extend(get_content())
        save_documents_csv(resource, CSV)
    parser()


если посмотреть на пайчарме то ворнинги и т.п отстутствует:
Screenshot_20220614_182340.png


@f22 спасибо тебе)) обычно я не обращаю внимание на синтаксис PEP и этих ворнингов, мне главное чтобы код работал)) но теперь буду знать и как исправлять ворнингов)))

а и ещё, рекомендую пользоваться этой руководстве по PEP8
Про библиотеке fake_useragent я установил, вызываю его но получаю вот такой вот ошибку
Screenshot_20220614_183900.png

видимо внутрення ошибка
 
Последнее редактирование:
  • Нравится
Реакции: OldGuard и f22
2
@f22 спасибо тебе)) обычно я не обращаю внимание на синтаксис PEP и этих ворнингов, мне главное чтобы код работал)) но теперь буду знать и как исправлять ворнингов)))
Пожалуйста)
Когда код выглядит опрятно, читать и воспринимать его гораздо проще)

видимо внутрення ошибка
Нет, дело не в ошибке.
Вы читайте документацию по модулю - вот же на главной странице:
1655222578265.png

Сначала нужно создать экземпляр класса UserAgent(), а потом уже получить у него нужное поле
Или получить поле сразу:
1655222639516.png


А вы зачем-то обновлять его полезли)
 
  • Нравится
Реакции: MySystem32
1
  • Нравится
Реакции: MySystem32
1
Пожалуйста)
Когда код выглядит опрятно, читать и воспринимать его гораздо проще)


Нет, дело не в ошибке.
Вы читайте документацию по модулю - вот же на главной странице:
Посмотреть вложение 60487
Сначала нужно создать экземпляр класса UserAgent(), а потом уже получить у него нужное поле
Или получить поле сразу:
Посмотреть вложение 60488

А вы зачем-то обновлять его полезли)
Ах, да емае почему я такой не внимательный, кстати если написать my_ua.firefox он выводит файрвокс юзер агента?
 
  • Нравится
Реакции: MySystem32
1
Мб, сделаю парсер для просмотра ресурсов с приватных контент, хз, с моего акка надо кукисы впихать или же авторизацию сделать