2ch
2ch copied to clipboard
Набор скриптов для двач 2ch.hk
О проекте
Хочешь скачать все файлы с /b или другого раздела? И без дубликатов? И только файлы больше/меньше X Килобайт? Или только картинки/только видео? Или файлы только с конкретного треда? Или тебе нужен трекер, который будет отбирать треды по ключевым словам? Всё это здесь! И даже больше!
В репозитории представлен готовый набор скриптов для двача, все скрипты можно кастомизировать под свои задачи. При минимальных знаниях питона можно с легкостью написать скрипт под свои нужды. Вся информация ниже.
Установка
Установите python
Скачайте zip архив или:
git clone https://github.com/diademoff/2ch
Установите зависимости:
cd 2ch
pip install -r requirements.txt
Запускайте нужный скрипт:
python {название скрипта}.py
Список скриптов
- Скачать все файлы и посты треда
thread_saver.py
- Уведомления о новых тредах на досках
tracker.py
- Самые популярные треды на доске
popular.py
- Скачивать все файлы доски
board_media.py
Редактирование скриптов
Все скрипты можно редактировать под ваши задачи.
-
thread_saver.py
-
FOLDER = 'saver'
- Изменить имя папки, в которую будут сохраняться файлы -
SAVE_MEDIA
- Сохранять ли изображения и видео -
DELAY
- Интервал обновления в секундах
-
-
tracker.py
-
text_limit = 155
- Изменить длину строки -
board_names = 'b news sex v hw gg dev soc rf ma psy fet'
- Изменить список досок (писать через пробел) -
KEY_WORDS
- Указать ключевые слова
-
-
popular.py
-
text_limit = 164
- Длина строки -
max_lines = 55
- Максимальное количество строк в выводе -
board_name = 'b'
- Доска, которая парсится -
KEY_WORDS
- Выводить треды только с ключевыми словами
-
-
board_media.py
-
BOARD = 'b'
- Имя борды, с которой скачивать файлы -
FOLDER_NAME = 'media'
- Имя папки, в которую скачивать файлы -
KEY_WORDS = []
- Отбирать треды по ключевым словам, если ключевые слова не указаны, то будут скачиваться файлы всех тредов -
EXTENSIONS = []
- Файлы с какими расширениями скачивать -
MAX_FILE_SIZE
- Задать максимальный размер файла в Килобайтах -
MIN_FILE_SIZE
- Задать минимальный размер файла в Килобайтах
-
FAQ
- Скрипт не запускается.
Проверьте установлены ли зависимости: pip install -r requirements.txt
. Проверьте кодировку файлов. Проверьте, что у вас установлена версия Python > 3.
- Как сравниваются изображения?
Изображения сравниваются по содержимому. Даже если у изображений разное расширение png
и jpg
, или разный размер они всё равно будут распознаны как одинаковые.
- Ты используешь api двача?
Да. А конкретно:
https://2ch.hk/makaba/mobile.fcgi?task=get_thread&board={board_name}&thread={num}&post=1
http://2ch.hk/{name}/threads.json
- Зачем тебе beautiful soup?
Преимущественно чтобы убирать html теги в постах. Если в посте жирный текст, то получается так:
<strong>текст</strong>
. Этот тэг нужно убрать, чтобы остался только текст.
- Как указать ключевые слова?
Откройте нужный скрипт и отредактируйте по образцу. Обратите внимание на форматирование, запятые и кавычки.
KEY_WORDS = [
"цуиь",
"mp4"
]
- Скрипты кроссплатформенные?
Да. Скрипты были проверены на Linux и Windows.
Для разработчиков
Весь api хранится в файле dvach.py
. Подключаем:
import dvach
Структура
-
Board
-
name: str
- Имя доски -
posts: dict
- Список постов, это словарь. Ключ - это номер треда, значение - переменная типаThread
-
json_link: str
- Ссылка на json тредов -
from_json()
- Получить объектBoard
из json'а -
json_download()
- Скачать json доски -
thread_exists()
- Есть ли на доске тред с указанным номером -
update_threads()
- Обновить список тредов на доске -
sort_threads_by_posts()
- Отсортировать список тредов по количеству постов, чем ближе элемент к началу списка, тем больше в нем постов -
get_new_threads()
- Сравнить текущий список тредов с другим и получить словарь новых тредов -
get_dead_threads()
- Сравнить текущий список тредов с другим и получить словарь утонувших тредов
-
-
Thread
-
comment: str
- Текст в ОП посте -
num: str
- Номер треда -
posts_count: int
- Количество постов -
score: float
- Сколько очков у треда -
subject: str
- Сокращенныйcomment
-
views: int
- Количество просмотров -
unique_posters: int
- Количество уникальных просмотров (появится после обновления постов) -
board_name: str
- Какой доске принадлежит тред -
posts = []
- Список постов -
get_link: str
- Ссылка на тред -
get_op_post: Post
- Получить ОП-пост -
json_posts_link: str
- Ссылка на json треда -
save(path)
- сохранить в html посты треда в указанную папку -
IsOk()
- Подходит ли тред по заданным ключевым словам -
update_posts()
- Скачать json и обновить их список, вызывает функциюget_posts()
-
get_posts()
- Спарсить json и обновитьunique_posters
иposts
-
json_download()
- Получить json постов в чистом виде
-
-
Post
-
comment: str
- Текст -
date: str
- Дата поста -
email: str
-
op: int
-
num: str
- Номер -
files: []
- Список файлов
-
-
Post_file
-
displayname: str
- Отображаемое имя -
name: str
- Имя -
download_link: str
- Ссылка на скачивание -
width: int
- Ширина -
height: int
- Высота -
size: int
- Размер файла -
IsImage: bool
- Является ли файл изображением -
IsVideo: bool
- Является ли файл видео -
save()
- Сохранить файл по указанному пути -
IsOk()
- Подходит ли файл по заданным расширениям, максимальному и минимальному размеру
-
Доски
Класс Board
позволяет взаимодействовать с досками (b, news, po, soc и т.д).
Объявление:
board = dvach.Board('b')
Теперь в переменной board
хранится доска b
, но там нет никакой информации, кроме названия доски. Чтобы получить список тредов на доске:
board.update_threads()
Теперь в поле threads
находится словарь с тредами. Ключ - это номер треда, значение - это тред (Thread
).
Получить список с номерами тредов:
# Список из номеров тредов, каждый номер имеет строковой тип.
thread_nums = list(board.threads.keys())
Отсортируем по популярности и снова получим список номеров тредов:
board.sort_threads_by_posts()
thread_nums = list(board.threads.keys())
Первый элемент теперь является номером самого популярного треда:
most_popular_num = thread_nums[0]
Треды
Мы получили номер самого популярного треда, теперь получим сам тред из словаря threads
:
thread = board.threads[most_popular_num]
В этом словаре значение имеет тип Thread
. Посмотрим тип переменной thread
:
print(type(thread))
Получим: <class 'dvach.Thread'>
Получим список постов в треде:
print(f"Количество постов (длина posts): {len(thread.posts)}")
print(f"Количество постов (posts_count): {thread.posts_count}")
thread.update_posts()
print(f"Количество постов (длина posts): {len(thread.posts)}")
print(f"Уникальных просмотров: {thread.unique_posters}")
На выходе получим:
Количество постов (длина posts): 0
Количество постов (posts_count): 60
Количество постов (длина posts): 64
Уникальных просмотров: 34
unique_posters
- появляется только после вызова update_posts()
или get_posts()
.
Получение количества постов с помощью len(thread.posts)
является более точным, но требует загрузки всех постов, в то время как thread.posts_count
известно во время получения тредов на доске.
Сохранение треда в html
Для сохранения треда используйте класс HtmlGenerator
и метод get_thread_htmlpage
. Этот метод возвращает html код, который можно сохранить в файл.
op_file = thread.posts[0].files[0] # Картинка в ОП-посте
img_path = os.path.normpath(f'./{op_file.name}') # Путь, куда мы ее сохраним
op_file.save(img_path) # Сохраняем картинку
# Получаем html
html = dvach.HtmlGenerator.get_thread_htmlpage(thread, img_path)
# Создаём файл
file = open(f'thread_{thread.num}.html', 'w')
# Записывает туда html страницу
file.write(html)
Или используйте функцию:
# Файл сохранится в папку, в которой выполняется скрипт с именем thread_{num}.html
thread.save('.')
Посты
После получения списка постов с помощью update_posts()
в поле posts
появился список постов начиная с ОП-поста.
Посмотрим второй пост в треде:
post = thread.posts[1]
print(f"Номер: {post.num}")
print(f"Текст: {post.comment}")
print(f"Количество файлов: {len(post.files)}")
На выходе получаем:
Номер: 210762237
Текст: Бамп
Количество файлов: 1
Файлы
Теперь получим первый файл в посте, если файл есть:
if len(post.files) > 0:
file = post.files[0]
print(type(file))
На выходе получим: <class 'dvach.Post_file'>
Посмотрим больше информации о файле:
print(f"Имя файла: {file.name}")
print(f"Ширина: {file.width}")
print(f"Высота: {file.height}")
print(f"Отображаемое имя: {file.displayname}")
print(f"Ссылка: {file.download_link}")
На выходе:
Имя файла: 16200245064090.jpg
Ширина: 3118
Высота: 1754
Отображаемое имя: 1620024504280.jpg
Ссылка: https://2ch.hk/b/src/245763818/16200245064090.jpg
Можно легко сохранить файл:
file.save(file.name)
Файл будет сохранен в директорию в которой выполняется скрипт с именем 16200245064090.jpg
Можно указать кастомный путь:
file.save(f"/home/username/{file.name}")
Итого
Весь код, используемый в примерах:
import dvach
import os
# Объявить доску
board = dvach.Board('b')
# Скачать треды
board.update_threads()
# Получить список номеров тредов
thread_nums = list(board.threads.keys())
# Отсортировать по количеству постов
board.sort_threads_by_posts()
# Обновить список с номерами тредов
thread_nums = list(board.threads.keys())
# Номер самого популярного треда
most_popular_num = thread_nums[0]
# Самый популярный тред
thread = board.threads[most_popular_num]
# Посмотреть тип переменной
print(type(thread))
print(f"Количество постов (длина posts): {len(thread.posts)}")
print(f"Количество постов (posts_count): {thread.posts_count}")
# Скачать посты
thread.update_posts()
print(f"Количество постов (длина posts): {len(thread.posts)}")
print(f"Уникальных просмотров: {thread.unique_posters}")
op_file = thread.posts[0].files[0] # Картинка в ОП-посте
img_path = os.path.normpath(f'./{op_file.name}') # Путь, куда мы ее сохраним
op_file.save(img_path) # Сохраняем картинку
# Получаем html
html = dvach.HtmlGenerator.get_thread_htmlpage(thread, img_path)
# Создаём файл
file = open(f'thread_{thread.num}.html', 'w')
# Записывает туда html страницу
file.write(html)
# Получить второй пост (который сразу после ОП-поста)
post = thread.posts[1]
print(f"Номер: {post.num}")
print(f"Текст: {post.comment}")
print(f"Количество файлов: {len(post.files)}")
if len(post.files) > 0:
# Получить первый файл
file = post.files[0]
print(type(file))
print(f"Имя файла: {file.name}")
print(f"Ширина: {file.width}")
print(f"Высота: {file.height}")
print(f"Отображаемое имя: {file.displayname}")
print(f"Ссылка: {file.download_link}")
# Сохранить файл
file.save(file.name)
# file.save(f"/home/username/{file.name}")