Seleniumとマルコフ連鎖を使用して自動文章生成と自動投稿をする方法

seleniumとマルコフ連鎖で自動文章生成と自動投稿

こんにちは、ボーノです。

今回は、Seleniumとマルコフ連鎖を使って、自動での文章生成と自動でのWordpressへの投稿のデモをやってみます。

今回はアフィリエイターに方に耳寄りの情報です。

一部のアフィリエイターは、新規・中古ドメインをいくつも用意し、最初は「適当な」記事を仕込んでおいて、順位が上がってきたらちゃんとした記事を入れる、という事を行っています。
その「適当な」記事を作成するツールが世の中にはあります(例えばラクキジやCワードなど)

しかし、実はこの「適当な」記事は、Seleniumとマルコフ連鎖を使用する事で自動生成し、且つ自動投稿する事が可能なんです。

フローとしては下記になります。

  1. 狙いたいキーワードでGoogle検索
  2. 上位ページの本文を取得
  3. 2の文字列を元に、マルコフ連鎖で新たな記事を生成
  4. Seleniumでアフィリエイトサイトに自動ログイン
  5. 3で作成した記事を投稿・公開
  6. 上記1〜5をアフィリエイトサイトの分だけ繰り返す

このように、ブラウザ自動化はアイデア次第では応用例が無限にあるので、皆さんもやりたい事を明確にして、トライしてみてはいかがでしょうか?

YouTubeでのデモ

使用したコード

実際に使用しているコードです。
ご自由にお使い下さい!

############################################################################################################
# 記事自動ポスト サテライト用 マルコフ連鎖使用 V1
# ・メインキーワードで検索して上位10個から1つのサイトを決定
# ・記事の見出しを全て取得→見出しは最大10個、10文字以下は除外
# ・本文をマルコフ連鎖で作成
# ・自動でwordpressに投稿
############################################################################################################

import os # ディレクトリの操作用
from selenium.webdriver import Chrome, ChromeOptions # ヘッドレスブラウザ
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
#所定時間待機用
import time
#正規表現用
import re
#キー操作用
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
#pythonでコピペをする用
import pyperclip
#リンクファイル読み込み用
import csv
#YouTubeタイトルに絵文字が含まれているかを検知する用
#import emoji
import sys
#メモリ不足で重くなるのを解消する 参考:https://iseed.jp/selenium-tips/
#Options.add_argument('--disable-dev-shm-usage')
#ポップアップアラートポップアップアラートをクリックする用
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.alert import Alert

#乱数生成用
import random
#Beautiul soup用
import requests
from bs4 import BeautifulSoup

#マルコフ連鎖用
import re
import MeCab
from collections import deque

#絵文字駆逐用
import emoji

#アラート用
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

#辞書の順番を保つ(通常の辞書は順番情報は持たないため順番がランダムになる)
from collections import OrderedDict

######################################################
# サイト設定
######################################################

#サテライトサイト情報
site_dict = OrderedDict()
site_dict = {
'キーワード':'サイトURL',
}

#wordpressログイン情報
USER = 'ユーザ名'
PASS = 'パスワード'

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

selected_site_url = '' #Google検索でランダムで選んだ1つのサイト
first_midashi = 0 #一番最初の見出し (記事のタイトルに設定する用)

######################################################
# 初期設定
######################################################

#selenium用ユーザプロファイルを使用する場合
#option設定。ログイン状態を保持する https://rabbitfoot.xyz/selenium-chrome-profile/
PROFILE_PATH = 'プロファイルのパス'
PROFILE_DIRECTORY = 'プロファイルが保存されているディレクトリ'

options = Options()
#Driverの読み込みとラクキジ拡張機能の読み込み
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)

######################################################
# 絵文字除去
######################################################

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

######################################################
# Googleでサイトを1つ決定し、見つかった記事から見出しの取得
######################################################

def getMidashis(word):
    global selected_site_url

    midashis = []

    #Googleでwordを検索
    page_num = random.randrange(9)*10 #1〜10ページ目の範囲でkennsaku
    url = 'https://www.google.com/search?start='+ str(page_num) +'&q=' + word
    driver.get(url)
    time.sleep(2)

    #検索結果からランダムで記事を選択
    index_num = random.randrange(7) + 1 #1〜10個目の記事からランダムに選択 広告が入ってると10を超える場合あるけど無視

    elems = driver.find_elements_by_xpath('//*[@class="yuRUbf"]/a')
    selected_site_url = elems[index_num].get_attribute('href')
    print(selected_site_url)

    #見出しタグを取得
    r = requests.get(selected_site_url)
    soup = BeautifulSoup(r.content, 'lxml')

    h2s = soup.find_all('h2')
    h3s = soup.find_all('h3')

    for i in range(len(h2s)):
        midashis.append(h2s[i])
    for i in range(len(h3s)):
        midashis.append(h3s[i])

    print(midashis)

    return midashis

######################################################
# サイトの本文を全て取得
######################################################

def getBody(url):
    driver.get(url)
    time.sleep(2)

    r = requests.get(url)
    soup = BeautifulSoup(r.content, 'lxml')

    body = soup.body.get_text()

    #絵文字除去
    body = remove_emoji(body)
    return body

######################################################
# マルコフ連鎖の準備
# https://qiita.com/k-jimon/items/f02fae75e853a9c02127
######################################################

def wakati(text):
    t = MeCab.Tagger("-Owakati")
    parsed_text = ""
    for one_line_text in one_sentence_generator(text):
        parsed_text += " "
        parsed_text += t.parse(one_line_text)
    wordlist = parsed_text.rstrip("\n").split(" ")
    return wordlist

def one_sentence_generator(long_text):
    sentences = re.findall(".*?。", long_text)
    for sentence in sentences:
        yield sentence

order = 2
#まずはモデルを作成する
def make_model(text):
    model = {}
    wordlist = wakati(text)
    queue = deque([], order)
    queue.append("[BOS]")
    for markov_value in wordlist:
        if len(queue) == order:
            if queue[-1] == "。":
                markov_key = tuple(queue)
                if markov_key not in model:
                    model[markov_key] = []
                model[markov_key].append("[BOS]")
                queue.append("[BOS]")

            markov_key = tuple(queue)      
            if markov_key not in model:
                model[markov_key] = []
            model[markov_key].append(markov_value)
        queue.append(markov_value)
    return model

#作成したモデルを使って文章を新しく作り出す
def make_sentence(model, sentence_num=10, seed="[BOS]", max_words = 1000):    
    sentence_count = 0

    key_candidates = [key for key in model if key[0] == seed]
    if not key_candidates:
        print("Not find Keyword")
        return
    markov_key = random.choice(key_candidates)
    queue = deque(list(markov_key), order)

    sentence = "".join(markov_key)

    for _ in range(max_words):
        markov_key = tuple(queue)
        next_word = random.choice(model[markov_key])
        sentence += next_word
        queue.append(next_word)

        if next_word == "。":
            sentence_count += 1
            if sentence_count == sentence_num:
                break

        #[BOS]の文字列が邪魔なので削除する
        sentence = sentence.replace('[BOS]', '')
    return sentence

######################################################
# マルコフ連鎖でオリジナル文章生成
######################################################

def makeMarkovBody(body):
    text = body
    order = 3
    model = make_model(text)
    markovbody = make_sentence(model)
    return markovbody

######################################################
# 見出しとオリジナル文章を合体
######################################################

def makeArticle(midashis, body):
    global first_midashi
    article = ''
    midashi_num = 0
    first_midashi = 0
    for i in range(len(midashis)):
        if len(midashis[i].text) > 10: #見出しの文字数は一定数以上にしてゴミは除去
            if first_midashi == 0: #一番最初の10文字以上の見出しを入れる
                first_midashi = i
            midashi_num = midashi_num + 1
            if midashi_num  5: #見出しは10個まで
                article = article+'

'+midashis[i].text+'

' markovbody = makeMarkovBody(body) article = article+markovbody return article ###################################################### # wordpressの操作 ###################################################### #wordpressログインページにアクセス def postWordpress(domain, article, midashis): global first_midashi #Wordpressにログイン url_login= domain + "/wp-login.php" driver.get(url_login) time.sleep(1) print(domain + 'のログインページにアクセスしました') #IDとパスワードのフォームに入力 elem = driver.find_element_by_id('user_login') elem.clear() elem.send_keys(USER) elem = driver.find_element_by_id('user_pass') elem.clear() elem.send_keys(PASS) print("フォームを送信") time.sleep(5) #ログインボタンを押してログイン browser_from = driver.find_element_by_name('wp-submit') browser_from.click() time.sleep(1) #テスト用 本当は1 print("情報を入力してログインボタンを押しました") #新規投稿ページにアクセス url_login= domain + "/wp-admin/post-new.php" driver.get(url_login) time.sleep(1) print(domain + 'の新規投稿ページにアクセスしました') #タイトルを入力(一番最初の見出しをいれる) title = driver.find_element_by_id('title') title.send_keys(midashis[first_midashi].text) #テキストタブをクリック elem = driver.find_element_by_id('content-html') elem.click() #ラク記事で生成した内容をコンテンツに追加 content = driver.find_element_by_id('content') content.send_keys(article) time.sleep(1) #更新ボタンが見えるところまでスクロール driver.execute_script('window.scrollTo(0, 0);') #注意!Seleniumでは画面で表示している領域の外にあるボタンはクリックできない! #設定を保存 time.sleep(1) #エラー出たのでここに挟んだ publish_post = driver.find_element_by_id('publish') publish_post.send_keys(Keys.SPACE) time.sleep(10) #公開までに5秒くらいかかった print('\n\n') num = 0 for word, domain in site_dict.items(): print(num) print(domain) num = num + 1 midashis = [] while 1: midashis = getMidashis(word) time.sleep(2) #これないと短時間にリクエストが発生してHTTPSConnectionPoolエラーになる if len(midashis) > 0: #見出しがないサイトがあるので break body = getBody(selected_site_url) article = makeArticle(midashis, body) if len(article) > 300: #中身がないサイトの場合は除去 300文字は目安 print('big article!!') postWordpress(domain, article, midashis) else: print('small article!!') print('\n\n') #プロセスを終了(これやらないとゾンビプロセスが増える) driver.quit() print('DONE!')

関連リンク

マルコフ連鎖プログラム引用元

https://qiita.com/k-jimon/items/f02fa…​
(このページはめちゃくちゃお勧めです!orderの数値などを変えると色々と結果が変わるようです)

Selenium

https://www.selenium.dev/documentatio…​

ラクキジ

https://rakukiji.com/

Cワード

http://c-word.biz/

まとめ

デモでも説明したように、Seleniumとマルコフ連鎖を使用して、適当な記事を自動で生成して、しかもそれをWordpressに投稿することは可能です。

このように、ブラウザ自動化はアイデア次第で色んなことが実現できるので、ぜひ皆さんも覚えてみてはいかがでしょうか。

ソフトウェアの知識がほとんどない自分でも作れたので、絶対皆さんもできると断言します。

不明な点などあったら問い合わせフォームよりご質問ください。

それでは。