【コード公開】5chまとめサイト自動投稿システム

寝ながら稼ぐ

最近、不労所得を得る事を目的に自動化にハマっており、いくつかシステムを作りました。

その一貫で5chまとめサイトに自動投稿するシステムを作ったので、ここではそのデモとコードを紹介します。

5chまとめサイト自動投稿システムのデモ

日本語版

English

使用環境

使用環境としては下記を使用しています。

  • JupyterLab Version 2.1.5
  • Selenium
  • Mac OS Catalina 10.15.2
  • Google Chrome 86.0.4240.75

自動投稿システムで使用したコード

下記に、そのデモで実際に使用したコードの一部を貼り付けておきます。

元々は全て貼り付ける予定でしたが、Amazonの電子書籍という形で出版する事にしました。
Kindle Unlimited(読み放題サービス)に加入している方であれば無料で中身を見れるので、そちらで確認してみてください。

URLはこちらです。

5chまとめ「自動」投稿システム|JupyterLabとSeleniumで実現

USER、PASS、ファイルパスはご自身で設定したものをお使い下さい。

基本的にはそのまま使用する事ができると思いますが、Wordpressのバージョンやウェブサイトのアップデート等により、正常に動作しない場合もあります。
その際はお気軽にご相談ください(エラー画面と一緒にお問い合わせコーナーから質問を投げてください)。

Beatutiful soupやSeleniumは便利なのは良いですが、環境の影響をうけやすくてメンテナンスが必要なのがネックですね。

#!/usr/bin/env python
# coding: utf-8

#ブラウザ操作用
from selenium import webdriver
#recaptcha対策で常にログイン状態を保持するためにoptionでargumentが必要
from selenium.webdriver.chrome.options import Options
#所定時間待機用
import time
#データ解析用
import pandas as pd
#HTML解析用
from bs4 import BeautifulSoup
#HTTPリクエスト用
import urllib.request as req
#相対URL→絶対URL変換用
import urllib
#画像保存フォルダ作成用
from pathlib import Path
#リンクファイル読み込み用
import csv
#javascriptでボタンをクリックする用
from selenium.webdriver.common.action_chains import ActionChains
#selectタグを選択できるようにする
from selenium.webdriver.support.ui import Select
#絵文字駆逐用
import emoji
#エンターキーを押す用
from selenium.webdriver.common.keys import Keys
#chromeのユーザプロファイル新規作成用
import os
#Google画像検索取得用
from PIL import Image
import io
import requests
import hashlib
import random

#まとめくす ログイン情報
USER = "your_address"
PASS = "your_pass"

#selenium用ユーザプロファイルを使用する場合
#option設定。ログイン状態を保持する https://rabbitfoot.xyz/selenium-chrome-profile/
PROFILE_PATH = 'your_path'
PROFILE_DIRECTORY = 'your_profile'

options = Options()
options.add_argument("--user-data-dir=" + PROFILE_PATH)
options.add_argument("--profile-directory=" + PROFILE_DIRECTORY)
driver = webdriver.Chrome(executable_path = '/usr/local/bin/chromedriver', options = options)
driver.implicitly_wait(1)

######################################################
# youtuberリスト読み込み
######################################################

#キャプチャ画像のパス
listfile = 'your_file' #cronを使用する場合は絶対パスを使用

youtuber_list = []
with open(listfile) as f:
    all_youtuber = csv.reader(f)
    for youtuber in all_youtuber:
        youtuber_list.append(youtuber[0])
print(youtuber_list)

######################################################
# グローバル変数設定
######################################################

res_number = 0 #対象となるスレッドのレスの総数
is_succeeded = 0 #まとめくすでスレッドの取得が成功したら1, 失敗したら0
thread_title = '' #wordpressの投稿の記事タイトルにする用
yoyaku_is_succeeded = 0 #要約が成功したら1,失敗したら0
res_is_found = 0 #条件に合うレスが見つかったら1, 見つからなかったら0
img_is_existed = 0 #もしスレッド内に画像があったら、Google画像検索ではなくスレッド内の画像を使う
wp_is_succeeded = 0 #wordpressへの投稿が成功したら1

######################################################
# ログ速でホットなスレッドを取得
######################################################

#指定されたクエリからレスを取得する関数 (thread_numberで何個目のスレッドを取得するかを指定する)
def getReses(word):
    #res_numberがグローバル変数である事を教えてあげる必要あり
    global res_number
    global res_is_found

    res_is_found = 0 #フラグをリセット

    #まずはログ速の検索画面へ
    url = 'https://www.logsoku.com/search?q='+ word
    driver.get(url)
    time.sleep(1)
    print('ログ速ページにアクセスしました')

    #1ページ目の全てのスレッドのURLを取得
    logsoku_urls = []
    elems = driver.find_elements_by_css_selector('td.title > a')
    for i in range(len(elems)):
        for elem in elems:
            logsoku_url = elem.get_attribute('href')
            logsoku_urls.append(logsoku_url)

    #レスの数が少なかったら次のスレッドにする
    logsoku_resnumber = []
    nums = driver.find_elements_by_css_selector('td.length')

    #投稿が見つかったら
    if len(elems) > 0:
        for i in range(5):
            if i < len(elems):
                title = elems[i].text
                print('タイトルは ' + elems[i].text)
                print('レス数は ' + nums[i+1].text)

                if ('【悲報】' in title or '【朗報】' in title or '【速報】' in title or '【疑問】' in title or '【真実】' in title or '【衝撃】' in title or '【話題】' in title or '【訃報】' in title or '【報告】' in title or '【動画】' in title or '【画像】' in title) and int(nums[i+1].text) > 5 and len(elems[i].text) < 60 and not ('part' in elems[i].text or 'Part' in elems[i].text):
                    url = logsoku_urls[i]
                    #レスの数をグローバル変数に格納する (resesには改行タグが全ての行に含まれているので、正味のレスの数はその半分)
                    res_number = int(nums[i+1].text)
                    res_is_found = 1
                    break

    #レスが見つかった場合のみ
    if res_is_found == 1:

        driver.get(url)
        time.sleep(1)

        #1つ目の掲示板URLを取得
        board_url = driver.find_elements_by_class_name('nav-btn')[0].get_attribute('href') #欲しいURLは必ずnab-btnの1つ目にあったので
        #デフォルトだと最新の50記事しか取得しない。そのためURLの最後の"/l50"の4文字を削除
        if '/l50' in board_url:
            board_url = board_url.rstrip('/l50')
        print(board_url)

        #スレッドページへ
        driver.get(board_url)
        time.sleep(8)  #すごい遅い時あったので長めに待つ
        print('スレッドページにアクセスしました')

        #レスを取得 (URLを含んだ行は削除)
        l_removed_list = []
        #2ch.sc, 2ch.net, open2ch.net, bbspink.com でそれぞれ取得方法が異なるので注意!!
        if ('2ch.sc' in board_url) or ('5ch.sc' in board_url):
            elems = driver.find_elements_by_css_selector('dd.net')
            #サイトによっては、dd.netが存在せずddだけの場合もあったので
            if not elems:
                elems = driver.find_elements_by_css_selector('dd')
        elif ('2ch.net' in board_url) or ('5ch.net' in board_url):
            elems = driver.find_elements_by_css_selector('dd')
        elif ('open2ch.net' in board_url) or ('open5ch.net' in board_url):
            elems = driver.find_elements_by_css_selector('dd.mesg')
        elif 'bbspink.com' in board_url:
            elems = driver.find_elements_by_css_selector('dd')

        for elem in elems:
            elemtext = elem.text
            #レスごとに除去
            #if not '>>' in elemtext:
            #Lineごとに除去
            #URLが混じっていると文章要約制度が落ちるので除外
            l_removed = [line for line in elemtext.splitlines() if not (('http' in line) or ('tp:/' in line) or ('jpg' in line) or ('tps:/' in line) or ('jpeg' in line) or ('bmp' in line) or ('gif' in line) or ('png' in line) or ('mpg' in line) or ('>>' in line))]
            l_removed_list.append(l_removed)
            l_removed_list.append('\n')

        #レスを一つの文字列に合体
        gathered_reses = []
        for i in range(len(l_removed_list)):
            gathered_res = '\n'.join(l_removed_list[i]) #.joinができてなさそう。あとで要確認
            #絵文字除去
            gathered_res = remove_emoji(gathered_res)
            gathered_reses.append(gathered_res)

        print(gathered_reses)
        return gathered_reses, board_url

    else:
        print('今回は良いレスが見当たらなかったよ!')

#絵文字駆逐関数
def remove_emoji(src_str):
    return ''.join(c for c in src_str if c not in emoji.UNICODE_EMOJI)

困ったときはお気軽にご相談下さい

冒頭でも言いましたが、SeleniumやBeautiful soupは環境による影響を大きく受けます。

エラーが出て全然動かない、、というかたはお気軽にご相談ください。

あと1行ずつに細かいノウハウもあるので、そのあたりは余力があればまた動画やこちらのサイトで説明していきたいと思います。

「こんな自動化システムを作って欲しい」という相談も受け付けていますので、どしどしリクエスト下さい!

I’m receiving requests that relate to this kind of automatic system.
Don’t hesitate to contact me!