Python 3でWebページをスクレイピングしてTwitterにコンテンツを投稿する方法

著者はhttps://www.brightfunds.org/organizations/computer-history-museum[The Computer History Museum]を選択して、https://do.co/w4do-cta [Write for DOnations]の一部として寄付を受け取りましたプログラム。

前書き

Twitterボットは、ソーシャルメディアを管理し、マイクロブログネットワークから情報を抽出する強力な方法です。 Twitterの汎用APIを活用することにより、ボットは、ツイート、リツイート、「お気に入りツイート」、特定の関心を持つ人々のフォロー、自動返信など、多くのことを実行できます。 人々はボットの力を悪用し、他のユーザーにマイナスの体験をもたらす可能性がありますが、調査によれば、人々はTwitterボットを信頼できる情報源と見なしています。 たとえば、ボットを使用すると、あなたがオンラインでないときでもフォロワーをコンテンツに引き付けることができます。 一部のボットは、https://twitter.com/earthquakesSF?ref_src = twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor [@EarthquakesSF]のような重要かつ有用な情報を提供します。 ボットのアプリケーションは無限です。 2019年時点で、ボットはTwitterで約https://en.wikipedia.org/wiki/Twitter_bot [全ツイートの24%]を占めていると推定されています。

このチュートリアルでは、Python用のhttps://github.com/sixohsix/twitter [このTwitter APIライブラリ]を使用してTwitterボットを構築します。 TwitterアカウントのAPIキーを使用して、ボットを認証し、2つのWebサイトからコンテンツをスクレイピングできるを構築します。 さらに、これら2つのWebサイトのコンテンツを、設定された時間間隔で交互にツイートするようにボットをプログラムします。 このチュートリアルではPython 3を使用することに注意してください。

前提条件

このチュートリアルを完了するには、次のものが必要です。

ステップ1-開発者アカウントのセットアップとTwitter APIキーへのアクセス

ボットのコーディングを開始する前に、ボットのリクエストを認識するためにTwitterのAPIキーが必要になります。 この手順では、Twitter開発者アカウントを設定し、TwitterボットのAPIキーにアクセスします。

APIキーを取得するには、https://developer.twitter.com [developer.twitter.com]に移動し、ページの右上にある[適用]をクリックして、ボットアプリケーションをTwitterに登録します。

次に、[開発者アカウントに適用]をクリックします。

次に、[続行]をクリックして、このチュートリアルで作成するボットアプリケーションにTwitterユーザー名を関連付けます。

image:https://assets.digitalocean.com/articles/TwitterPython/step1a.png [ボットとのTwitterユーザー名の関連付け]

次のページでは、このチュートリアルの目的で、個人教育用のボットを構築するため、[個人使用のためのアクセスをリクエストしています]オプションを選択します。

image:https://assets.digitalocean.com/articles/TwitterPython/step1b.png [Twitter API個人使用]

*アカウント名*と*国*を選択したら、次のセクションに進みます。 *どのようなユースケースに興味がありますか?*の場合は、*ツイートの公開とキュレーション*および*学生プロジェクト/コード化の学習*オプションを選択します。 これらのカテゴリは、このチュートリアルを完了する理由を最もよく表しています。

image:https://assets.digitalocean.com/articles/TwitterPython/step1c.png [Twitterボットの目的]

次に、構築しようとしているボットの説明を入力します。 Twitterは、ボットの悪用から保護するためにこれを必要とします。 2018年に彼らはそのような審査を導入しました。 このチュートリアルでは、https://thenewstack.io [The New Stack]およびhttps://blog.coursera.org [The Coursera Blog]から技術に焦点を当てたコンテンツをスクレイピングします。

  • description *ボックスに入力する内容を決定するとき、このチュートリアルの目的のために、次の行で回答をモデル化します。

_newstack.io(The New Stack)やblog.coursera.org(Courseraのブログ)などのWebサイトからコンテンツをスクレイプし、それらから引用をツイートするTwitterボットを作成するチュートリアルを進めています。 スクレイピングされたコンテンツは集約され、Pythonジェネレーター関数を介してラウンドロビン方式でツイートされます。

最後に、あなたの製品、サービス、または分析によってTwitterコンテンツまたは派生情報を政府機関が利用できるようにするために*いいえ*を選択します

image:https://assets.digitalocean.com/articles/TwitterPython/step1d.png [Twitter Bot Intent]

次に、Twitterの利用規約に同意し、[アプリケーションを送信]をクリックして、メールアドレスを確認します。 このフォームを送信すると、Twitterから確認メールが送信されます。

メールを確認すると、お申し込みプロセスのフィードバックフォームを含む[審査中のお申し込み]ページが表示されます。

また、レビューに関してTwitterから別のメールを受け取ります。

image:https://assets.digitalocean.com/articles/TwitterPython/step1e.png [アプリケーションレビューメール]

Twitterのアプリケーションレビュープロセスのタイムラインは大幅に異なる場合がありますが、多くの場合、Twitterは数分以内にこれを確認します。 ただし、アプリケーションのレビューにこれより時間がかかる場合は珍しくありません。1〜2日以内にレビューを受け取る必要があります。 確認を受け取ると、Twitterはキーの生成を許可します。 developer.twitter.com/appsでアプリの詳細ボタンをクリックした後、*キーとトークン*タブでこれらにアクセスできます。

最後に、アプリのページの* Permissions タブに移動し、ツイートコンテンツも書きたいので、 Access Permission オプションを Read and Write *に設定します。 通常、傾向の分析、データマイニングなどの研究目的で読み取り専用モードを使用します。 最後のオプションでは、チャットボットはダイレクトメッセージへのアクセスを必要とするため、ユーザーはチャットボットを既存のアプリに統合できます。

image:https://assets.digitalocean.com/articles/TwitterPython/step1f.png [Twitterアプリの権限ページ]

Twitterの強力なAPIにアクセスできます。これはボットアプリケーションの重要な部分です。 次に、環境をセットアップして、ボットの構築を開始します。

ステップ2-Essentialsの構築

このステップでは、APIキーを使用してTwitterでボットを認証するコードを記述し、Twitterハンドルを介してプログラムによる最初のツイートを行います。 これは、https://thenewstack.io [The New Stack]およびhttps://blog.coursera.org [Coursera Blog]からコンテンツをスクレイピングするTwitterボットを構築するという目標への道のりの良いマイルストーンとして機能します。定期的にツイートします。

最初に、プロジェクトフォルダーとプロジェクトの特定のプログラミング環境を設定します。

プロジェクトフォルダーを作成します。

mkdir

プロジェクトフォルダーに移動します。

cd

次に、プロジェクト用の新しいPython仮想環境を作成します。

python3 -m venv

次に、次のコマンドを使用して環境をアクティブ化します。

source /bin/activate

これにより、ターミナルウィンドウのプロンプトに `(bird-env)`プレフィックスが付加されます。

テキストエディタに移動して、Twitter APIキーを保存する `+ credentials.py +`というファイルを作成します。

nano credentials.py

次のコンテンツを追加し、強調表示されたコードをTwitterのキーに置き換えます。

bird / credentials.py

ACCESS_TOKEN=''
ACCESS_SECRET=''
CONSUMER_KEY=''
CONSUMER_SECRET=''

次に、Twitterにリクエストを送信するためのメインAPIライブラリをインストールします。 このプロジェクトでは、「+ nltk 」、「 requests 」、「 twitter 」、「 lxml 」、「 random 」、「 time 」のライブラリが必要です。 「 random 」と「 time +」はPythonの標準ライブラリの一部であるため、これらのライブラリを個別にインストールする必要はありません。 残りのライブラリをインストールするには、Pythonのパッケージマネージャーであるhttps://github.com/pypa/pip[pip]を使用します。

ターミナルを開き、プロジェクトフォルダーにいることを確認して、次のコマンドを実行します。

pip3 install lxml nltk requests twitter
  • + lxml +`および `+ requests +:Webスクレイピングに使用します。

  • + twitter:これは、TwitterのサーバーにAPI呼び出しを行うためのライブラリです。

  • + nltk +:(自然言語ツールキット)ブログの段落を文に分割するために使用します。

  • + random +:これを使用して、スクレイプされたブログ投稿全体の一部をランダムに選択します。

  • + time +:特定のアクションの後に定期的にボットをスリープさせるために使用します。

ライブラリをインストールしたら、プログラミングを開始する準備が整いました。 次に、ボットを実行するメインスクリプトに資格情報をインポートします。 `+ credentials.py `と共に、テキストエディターから `+`プロジェクトディレクトリにファイルを作成し、 `+ bot.py +`という名前を付けます。

nano bot.py

実際には、ボットがますます高度になるにつれて、ボットの機能を複数のファイルに分散します。 ただし、このチュートリアルでは、デモ用にすべてのコードを単一のスクリプト「+ bot.py +」に入れます。

最初に、ボットを認証してAPIキーをテストします。 最初に、次のスニペットを `+ bot.py +`に追加します。

bird / bot.py

import random
import time

from lxml.html import fromstring
import nltk
nltk.download('punkt')
import requests
from twitter import OAuth, Twitter

import credentials

ここで、必要なライブラリをインポートします。いくつかのインスタンスでは、必要なhttps://www.digitalocean.com/community/tutorials/how-to-define-functions-in-python-3[functions]をライブラリからインポートします。 コードの後半で `+ fromstring `関数を使用して、スクレイプされたWebページの文字列ソースをツリー構造に変換し、ページから関連情報を簡単に抽出できるようにします。 「 OAuth 」は、キーから認証オブジェクトを構築するのに役立ちます。「 Twitter +」は、Twitterのサーバーとさらに通信するためのメインAPIオブジェクトを構築します。

次の行で `+ bot.py +`を拡張します:

bird / bot.py

...
tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')

oauth = OAuth(
       credentials.ACCESS_TOKEN,
       credentials.ACCESS_SECRET,
       credentials.CONSUMER_KEY,
       credentials.CONSUMER_SECRET
   )
t = Twitter(auth=oauth)

`+ nltk.download( 'punkt')`は、段落を解析し、それらを小さなコンポーネントにトークン化(分割)するために必要なデータセットをダウンロードします。 「 tokenizer +」は、英語で書かれた段落を分割するためのコードで後で使用するオブジェクトです。

`+ oauth `は、インポートされた ` OAuth `クラスにAPIキーを渡すことで構築される認証オブジェクトです。 ` t = Twitter(auth = oauth)`の行でボットを認証します。 ` ACCESS_TOKEN `と ` ACCESS_SECRET `は、アプリケーションの認識に役立ちます。 最後に、 ` CONSUMER_KEY `と ` CONSUMER_SECRET `は、アプリケーションがTwitterとやり取りする際のハンドルを認識するのに役立ちます。 この ` t +`オブジェクトを使用して、リクエストをTwitterに伝えます。

このファイルを保存し、次のコマンドを使用してターミナルで実行します。

python3 bot.py

出力は次のようになります。これは、認証が成功したことを意味します。

Output[nltk_data] Downloading package punkt to /Users/binaryboy/nltk_data...
[nltk_data]   Package punkt is already up-to-date!

エラーが表示された場合は、保存されたAPIキーをhttps://developer.twitter.com [Twitter開発者アカウント]にあるものと確認し、再試行してください。 また、必要なライブラリが正しくインストールされていることを確認してください。 そうでない場合は、再度 `+ pip3 +`を使用してインストールします。

これで、プログラムで何かをツイートすることができます。 スクリプトの実行後にPythonインタープリターを開くには、ターミナルで同じコマンドを `+ -i +`フラグを付けて入力します。

python3 -i bot.py

次に、次のように入力して、アカウント経由でツイートを送信します。

t.statuses.update(status="Just setting up my Twttr bot")

ブラウザでTwitterのタイムラインを開くと、タイムラインの上部に、投稿したコンテンツを含むツイートが表示されます。

image:https://assets.digitalocean.com/articles/TwitterPython/step2a.png [最初のプログラムによるツイート]

「+ quit()」または「 CTRL + D +」と入力して、インタープリターを閉じます。

これで、ボットにツイートする基本的な機能が追加されました。 有用なコンテンツをツイートするボットを開発するには、次のステップでWebスクレイピングを組み込みます。

ステップ3-ツイートコンテンツのWebサイトをスクレイピングする

より興味深いコンテンツをタイムラインに紹介するには、https://thenewstack.io [the New Stack]およびhttps://blog.coursera.org [Coursera Blog]からコンテンツをスクレイピングし、このコンテンツをツイート形式のTwitter。 通常、ターゲットWebサイトから適切なデータを取得するには、HTML構造を実験する必要があります。 このチュートリアルで作成するボットから送信される各ツイートには、選択したWebサイトからのブログ投稿へのリンクと、そのブログからのランダムな引用があります。 Courseraからコンテンツをスクレイピングするための特定の関数内でこの手順を実装するため、「+ scrape_coursera()+」という名前を付けます。

最初に `+ bot.py +`を開きます:

nano bot.py

ファイルの最後に `+ scrape_coursera()+`関数を追加します。

bird / bot.py

...
t = Twitter(auth=oauth)

ブログから情報を取得するには、まずCourseraのサーバーに関連するウェブページをリクエストします。 そのためには、 `+ requests `ライブラリの ` get()`関数を使用します。 ` get()`はURLを受け取り、対応するWebページを取得します。 したがって、 ` blog.coursera.org `を ` get()`の引数として渡します。 ただし、GETリクエストにヘッダーを指定する必要もあります。これにより、Coureraのサーバーが本物のクライアントとして認識されるようになります。 次の強調表示された行を ` scrape_coursera()+`関数に追加して、ヘッダーを提供します。

bird / bot.py

def scrape_coursera():

このヘッダーには、特定のオペレーティングシステムで実行されている定義済みのWebブラウザーに関する情報が含まれます。 この情報(通常は「+ User-Agent +」と呼ばれます)が実際のWebブラウザーとオペレーティングシステムに対応している限り、ヘッダー情報がコンピューターの実際のWebブラウザーとオペレーティングシステムと一致するかどうかは関係ありません。 したがって、このヘッダーはすべてのシステムで正常に機能します。

ヘッダーを定義したら、次の強調表示された行を追加して、ブログWebページのURLを指定してCourseraにGETリクエストを行います。

bird / bot.py

...
def scrape_coursera():
   HEADERS = {
       'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                     ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
       }

これにより、Webページがマシンにフェッチされ、Webページ全体の情報が変数 `+ r `に保存されます。 ` r `の ` content `属性を使用して、WebページのHTMLソースコードを評価できます。 したがって、 ` r.content +`の値は、ページを右クリックして* Inspect Element *オプションを選択し、ブラウザーでWebページを検査したときに表示される値と同じです。

ここでは、 `+ fromstring `関数も追加しました。 ウェブページのソースコードを ` lxml `ライブラリからインポートした ` fromstring `関数に渡して、ウェブページの ` tree `構造を構築できます。 この_tree_構造により、Webページのさまざまな部分に簡単にアクセスできます。 HTMLソースコードには、特定のツリーのような構造があります。すべての要素は ` <html> +`タグで囲まれ、その後ネストされます。

次に、ブラウザで「+ https://blog.coursera.org+」を開き、ブラウザの開発者ツールを使用してHTMLソースを調べます。 ページを右クリックして、* Inspect Element *オプションを選択します。 ブラウザの下部にウィンドウが表示され、ページのHTMLソースコードの一部が表示されます。

画像:https://assets.digitalocean.com/articles/TwitterPython/step3a.png [browser-inspect]

次に、表示されているブログ投稿のサムネイルを右クリックして調べます。 HTMLソースは、ブログのサムネイルが定義されている関連するHTML行を強調表示します。 このページのすべてのブログ投稿は、 `+ <div> `タグ内で_class_が `" recent "+`で定義されていることがわかります。

画像:https://assets.digitalocean.com/articles/TwitterPython/step3b.png [blog-div]

したがって、コードでは、https://www.w3schools.com/xml/xml_xpath.asp [XPath]を介してすべてのそのようなブログ投稿の `+ div +`要素を使用します。これは、ウェブページ。

そのためには、次のように `+ bot.py +`で関数を拡張します:

bird / bot.py

...
def scrape_coursera():
   HEADERS = {
       'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                     ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
                   }
   r = requests.get('https://blog.coursera.org', headers=HEADERS)
   tree = fromstring(r.content)

ここで、XPath+ tree.xpath()+`に渡される文字列)は、class `+" recent "+`のWebページソース全体からの `+ div +`要素が必要であることを伝えます。 `+ // +`はWebページ全体の検索に対応し、 `+ div +`は `+ div +`要素のみを抽出するよう関数に指示し、 `+ [@ class =" recent "] +`はそれらのみを抽出するように要求します+ class `属性の値が `" recent "`である ` div +`要素。

ただし、これらの要素自体は必要ありません。それらが指しているリンクのみが必要なので、個々のブログ投稿にアクセスしてコンテンツを取得できます。 したがって、ブログ投稿の以前の `+ div `タグ内にある ` href +`アンカータグの値を使用して、すべてのリンクを抽出します。

これまでのプログラムをテストするには、 `+ bot.py `の最後で ` scrape_coursera()+`関数を呼び出します。

保存して `+ bot.py +`を終了します。

次のコマンドで `+ bot.py +`を実行します:

python3 bot.py

出力には、次のようなURLのhttps://www.digitalocean.com/community/tutorials/understanding-lists-in-python-3[list]が表示されます。

Output['https://blog.coursera.org/career-stories-from-inside-coursera/', 'https://blog.coursera.org/unlock-the-power-of-data-with-python-university-of-michigan-offers-new-programming-specializations-on-coursera/', ...]

出力を確認した後、強調表示された最後の2行を `+ bot.py +`スクリプトから削除できます。

bird / bot.py

...
def scrape_coursera():
   ...
   tree = fromstring(r.content)
   links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')

次に、ブログ投稿からコンテンツを抽出するために、次の強調表示された行で `+ bot.py +`の関数を拡張します。

bird / bot.py

...
def scrape_coursera():
   ...
   links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')

各リンクを反復処理し、対応するブログ投稿を取得し、投稿からランダムな文を抽出し、対応するURLとともにこの文を引用としてツイートします。 ランダムな文の抽出には、次の3つの部分が含まれます。

  1. ブログ投稿のすべての段落をリストとして取得します。

  2. 段落のリストから段落をランダムに選択します。

  3. この段落からランダムに文を選択します。

ブログ投稿ごとにこれらの手順を実行します。 取得するには、リンクのGETリクエストを作成します。

ブログのコンテンツにアクセスできるようになったので、次の3つのステップを実行して必要なコンテンツを抽出するコードを紹介します。 3つのステップを実行するスクレイピング関数に次の拡張子を追加します。

bird / bot.py

...
def scrape_coursera():
   ...
   for link in links:
       r = requests.get(link, headers=HEADERS)
       blog_tree = fromstring(r.content)

最初のリンクを開いてブログの投稿を調べると、すべての段落がクラスとして「+ entry-content 」を持つ「 div 」タグに属していることがわかります。 したがって、すべての段落をリストとして抽出するには、「 paras = blog_tree.xpath( '// div [@ class = "entry-content"] / p')+ `」を使用します。

image:https://assets.digitalocean.com/articles/TwitterPython/step3c.png [段落を囲む部分]

リストの要素は_literal_段落ではありません。それらは + Element + _objects_です。 これらの_objects_からテキストを抽出するには、 `+ text_content()`メソッドを使用します。 この行は、Pythonのhttps://www.digitalocean.com/community/tutorials/understanding-list-comprehensions-in-python-3[_list comprehension_]設計パターンに従っています。単線。 ` bot.py `では、各段落要素_object_のテキストを抽出し、テキストが空でない場合は_list_に保存します。 この段落リストから段落をランダムに選択するには、 ` random +`モジュールを組み込みます。

最後に、この段落からランダムに文を選択する必要があります。この文は変数 `+ para `に保存されます。 このタスクでは、最初に段落を文に分割します。 これを達成する1つのアプローチは、Pythonの ` split()`メソッドを使用することです。 ただし、文は複数のブレークポイントで分割される可能性があるため、これは難しい場合があります。 したがって、分割タスクを簡素化するために、 ` nltk `ライブラリを介して自然言語処理を活用します。 チュートリアルの前半で定義した ` tokenizer +`オブジェクトは、この目的に役立ちます。

文章のリストができたので、 `+ random.choice()`を呼び出してランダムな文章を抽出します。 この文をツイートの引用にしたいので、280文字を超えることはできません。 ただし、審美的な理由から、大きすぎたり小さすぎたりしない文を選択します。 ツイート文の長さは60〜210文字にする必要があることを指定します。 ` random.choice()+`が選択する文は、この基準を満たさない場合があります。 適切な文を識別するために、スクリプトは10回試行し、毎回基準をチェックします。 ランダムに選択された文が基準を満たすと、ループから抜け出すことができます。

確率は非常に低くなりますが、10回の試行内でこのサイズの条件を満たしている文はない可能性があります。 この場合、対応するブログ投稿を無視して、次のブログ投稿に進みます。

引用する文ができたので、対応するリンクでツイートできます。 これを行うには、ランダムにピックアップされた文と対応するブログリンクを含む文字列を生成します。 この `+ scrape_coursera()+`関数を呼び出すコードは、生成された文字列をTwitterのAPI経由でTwitterに投稿します。

次のように関数を拡張します。

bird / bot.py

...
def scrape_coursera():
   ...
   for link in links:
       ...
       para_tokenized = tokenizer.tokenize(para)
       for _ in range(10):
           text = random.choice(para)
           if text and 60 < len(text) < 210:
               break

スクリプトは、先行する「+ for 」ループが中断しない場合にのみ「 else 」ステートメントを実行します。 したがって、ループがサイズ条件に適合する文を見つけることができない場合にのみ発生します。 この場合、この関数を呼び出すコードがツイートするものがないと判断できるように、 ` None `を生成します。 次に、関数を再度呼び出して、次のブログリンクのコンテンツを取得します。 しかし、ループが中断した場合、関数が適切な文を見つけたことを意味します。スクリプトは ` else +`ステートメントを実行せず、関数は単一の_whitespace_で区切られた文とブログリンクで構成される文字列を生成します。

`+ scrape_coursera()+`関数の実装はほぼ完了しています。 別のWebサイトをスクレイピングするために同様の機能を作成する場合は、Courserのブログをスクレイピングするために記述したコードの一部を繰り返す必要があります。 コードの一部の書き直しや重複を避け、ボットのスクリプトがhttps://en.wikipedia.org/wiki/Don%27t_repeat_yourself[DRY]原則(自分自身を繰り返さない)に従うようにするには、識別して抽象化します後で書かれたスクレーパー関数に何度も何度も使用するコードの一部を削除します。

関数がスクレイピングしているWebサイトに関係なく、段落をランダムに選択し、この選択した段落からランダムな文を選択する必要があります-これらの機能を別の関数で抽出できます。 その後、スクレーパー関数からこれらの関数を呼び出すだけで、目的の結果を得ることができます。 また、すべてのスクレーパー関数が使用できるように、「+ scrape_coursera()」関数の外側で「 HEADERS 」を定義することもできます。 したがって、次のコードでは、 ` HEADERS +`の定義がスクレーパー関数の定義の前にある必要があります。これにより、最終的に他のスクレーパーに使用できるようになります。

bird / bot.py

...






def scrape_coursera():
   r = requests.get('https://blog.coursera.org', headers=HEADERS)
   ...

段落オブジェクトのリストからランダムな段落を抽出するための `+ extract_paratext()`関数を定義できるようになりました。 ランダムな段落は、関数に ` paras +`引数として渡され、選択した段落のトークン化された形式を返します。これは、後で文の抽出に使用します。

bird / bot.py

...
HEADERS = {
       'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                     ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
       }










def scrape_coursera():
   r = requests.get('https://blog.coursera.org', headers=HEADERS)
   ...

次に、引数として取得したトークン化された段落から適切な長さ(60〜210文字)のランダムな文を抽出する関数を定義します。これは、「+ para 」と名付けられます。 そのような文が10回試行しても発見されない場合、関数は代わりに ` None `を返します。 次の強調表示されたコードを追加して、 ` extract_text()+`関数を定義します。

bird / bot.py

...

def extract_paratext(paras):
   ...
   return tokenizer.tokenize(para)














def scrape_coursera():
   r = requests.get('https://blog.coursera.org', headers=HEADERS)
   ...

これらの新しいヘルパー関数を定義したら、次のように `+ scrape_coursera()+`関数を再定義できます:

bird / bot.py

...
def extract_paratext():
   for _ in range(10):<^>
       text = random.choice(para)
   ...


def scrape_coursera():



   r = requests.get(url, headers=HEADERS)
   tree = fromstring(r.content)
   links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')

   for link in links:
       r = requests.get(link, headers=HEADERS)
       blog_tree = fromstring(r.content)
       paras = blog_tree.xpath('//div[@class="entry-content"]/p')





       yield '"%s" %s' % (text, link)

保存して `+ bot.py +`を終了します。

ここでは、「+ return 」ではなく「 yield 」を使用しています。これは、リンクを反復処理するために、スクレイパー関数がツイート文字列を1つずつ順番に提供するためです。 これは、 ` sc = scrape_coursera()`として定義されたスクレーパー ` sc `を初めて呼び出すと、スクレーパー関数内で計算したリンクのリストの最初のリンクに対応するツイート文字列を取得することを意味します。 インタプリタで次のコードを実行すると、 ` scrape_coursera()`内の ` links `変数に ` ["https://thenewstack.io/cloud-native-live-twistlocks-virtual-conference/"、"https://blog.coursera.org/unlock-the-power-of-data-with-python-university -of-michigan-offers-new-programming-specialization-on-coursera / "、…​] +`。

python3 -i bot.py

スクレーパーをインスタンス化し、 `+ sc +`と呼びます:

>>> sc = scrape_coursera()

現在はジェネレーターです。 Courseraから関連コンテンツを1つずつ生成またはスクレイピングします。 `+ sc `を介して ` next()+`を順番に呼び出すことで、スクレイピングされたコンテンツに1つずつアクセスできます。

>>> string_1 = next(sc)
>>> string_2 = next(sc)

これで、スクレイプされたコンテンツを表示するために定義した文字列を「+ print」できます。

>>> print(string_1)
"Other speakers include Priyanka Sharma, director of cloud native alliances at GitLab and Dan Kohn, executive director of the Cloud Native Computing Foundation." https://thenewstack.io/cloud-native-live-twistlocks-virtual-conference/
>>>
>>> print(string_2)
"You can learn how to use the power of Python for data analysis with a series of courses covering fundamental theory and project-based learning." https://blog.coursera.org/unlock-the-power-of-data-with-python-university-of-michigan-offers-new-programming-specializations-on-coursera/
>>>

代わりに `+ return `を使用すると、文字列を1つずつ順番に取得できなくなります。 ` scrape_coursera()`で単純に ` yield `を ` return `に置き換えると、最初の呼び出しで最初のものを取得する代わりに、常に最初のブログ投稿に対応する文字列を取得します。 2回目の呼び出しなどで。 すべてのリンクに対応するすべての文字列の_list_を返すように関数を変更できますが、それはより多くのメモリを消費します。 また、この種のプログラムは、_list_全体をすばやく必要とする場合、短時間でCourseraのサーバーに大量のリクエストを行う可能性があります。 これにより、ボットが一時的にWebサイトへのアクセスを禁止される可能性があります。 したがって、「 yield +」は、一度に1つずつ情報を取得するだけで十分なさまざまなスクレイピングジョブに最適です。

ステップ4-追加コンテンツのスクレイピング

このステップでは、https://thenewstack.io [thenewstack.io]のスクレーパーを構築します。 このプロセスは前のステップで完了したものと似ているため、簡単な概要になります。

ブラウザでWebサイトを開き、ページソースを調べます。 ここでは、すべてのブログセクションがクラス「+ normalstory-box」の「+ div」要素であることがわかります。

image:https://assets.digitalocean.com/articles/TwitterPython/step4a.png [The New Stack WebサイトのHTMLソース検査]

次に、 `+ scrape_thenewstack()+`という名前の新しいスクレーパー関数を作成し、その中からhttps://thenewstack.io [thenewstack.io]にGETリクエストを作成します。 次に、これらの要素からブログへのリンクを抽出し、各リンクを繰り返します。 これを実現するには、次のコードを追加します。

bird / bot.py

...
def scrape_coursera():
   ...
   yield '"%s" %s' % (text, link)

「+ verify = False 」フラグを使用するのは、ウェブサイトがセキュリティ証明書の有効期限が切れている場合があり、ここにあるように機密データが関与していない場合はアクセスできるためです。 ` verify = False`フラグは、` + requests.get`メソッドに証明書を検証せず、通常どおりデータの取得を続行するよう指示します。 それ以外の場合、メソッドは期限切れのセキュリティ証明書に関するエラーをスローします。

これで、各リンクに対応するブログの段落を抽出し、前の手順で作成した `+ extract_paratext()`関数を使用して、使用可能な段落のリストからランダムな段落を取り出すことができます。 最後に、 ` extract_text()`関数を使用してこの段落からランダムな文を抽出し、対応するブログリンクで ` yield +`します。 次の強調表示されたコードをファイルに追加して、これらのタスクを実行します。

bird / bot.py

...
def scrape_thenewstack():
   ...
   links = tree.xpath('//div[@class="normalstory-box"]/header/h2/a/@href')

   for link in links:

これで、一般的にスクレイピングプロセスに含まれるものがわかりました。 独自のカスタムスクレーパーを作成できるようになりました。たとえば、ランダムな引用ではなくブログ投稿の画像をスクレイピングできます。 そのために、関連する `+ <img> `タグを探すことができます。 識別子として機能するタグの正しいパスを取得したら、対応する属性の名前を使用してタグ内の情報にアクセスできます。 たとえば、画像をスクレイピングする場合、 ` src +`属性を使用して画像のリンクにアクセスできます。

この時点で、2つの異なるWebサイトからコンテンツをスクレイピングするための2つのスクレーパー関数を構築し、2つのスクレーパーに共通の機能を再利用するための2つのヘルパー関数も構築しました。 ボットがツイートする方法とツイートする方法を知ったので、スクレイピングされたコンテンツをツイートするコードを作成します。

ステップ5-スクレイピングされたコンテンツのツイート

このステップでは、ボットを拡張して2つのWebサイトからコンテンツを取得し、Twitterアカウント経由でツイートします。 より正確には、2つのWebサイトからのコンテンツを交互に、10分間隔で無期限にツイートする必要があります。 したがって、https://www.digitalocean.com/community/tutorials/how-to-construct-while-loops-in-python-3 [infinite while loop]を使用して必要な機能を実装します。 これを `+ main()+`関数の一部として実行します。これは、ボットが従うコアの高レベルプロセスを実装します。

bird / bot.py

...
def scrape_thenewstack():
   ...
   yield '"%s" %s' % (text, link)

最初に、前に定義したスクレイピング関数の名前のリストを作成し、それを `+ news_funcs `として呼び出します。 次に、実際のスクレーパー関数を保持する空のリストを作成し、そのリストに「 news_iterators 」という名前を付けます。 次に、 ` news_funcs `リストの各名前を調べて、 ` news_iterators `リストに対応するイテレーターを追加することにより、データを取り込みます。 Pythonの組み込みの ` globals()`関数を使用しています。 これは、変数名をスクリプト内の実際の変数にマップする辞書を返します。 イテレータは、スクレーパー関数を呼び出すときに取得するものです。たとえば、「 coursera_iterator = scrape_coursera()」と記述すると、「 coursera_iterator 」は「 next()」を呼び出すことができるイテレータになります。呼び出します。 各 ` next()`呼び出しは、 ` scrape_coursera()`関数の ` yield `ステートメントで定義されたとおりに、引用符とそれに対応するリンクを含む文字列を返します。 各 ` next()`呼び出しは、 ` scrape coursera()`関数の ` for`ループの1回の繰り返しを実行します。 したがって、 `+ scrape_coursera()`関数にブログリンクがある限り、 ` next()`呼び出しを行うことができます。 その数を超えると、「 StopIteration +」例外が発生します。

両方のイテレータが `+ news_iterators `リストに入力されると、メインの ` while `ループが開始されます。 その中には、各イテレータを通過し、ツイートされるコンテンツを取得しようとする「 for 」ループがあります。 コンテンツを取得した後、ボットはそれをツイートし、10分間スリープします。 イテレータに提供するコンテンツがこれ以上ない場合、 ` StopIteration +`例外が発生します。この例外では、イテレータを再インスタンス化して更新し、ソースWebサイト上の新しいコンテンツの可用性を確認します。 次に、可能な場合は次のイテレーターに進みます。 それ以外の場合、実行がイテレータリストの最後に達すると、最初からやり直して、次に利用可能なコンテンツをツイートします。 これにより、ボットは2つのスクレイパーから交互にコンテンツをツイートすることができます。

今残っているのは、 `+ main()+`関数を呼び出すことだけです。 スクリプトは、Pythonインタープリターによって_directly_と呼ばれるときにこれを行います。

bird / bot.py

...
def main():
   print('---Bot started---\n')<^>
   news_funcs = ['scrape_coursera', 'scrape_thenewstack']
   ...

以下は、 `+ bot.py +`スクリプトの完成バージョンです。 https://github.com/do-community/chirps [このGitHubリポジトリのスクリプト]を表示することもできます。

bird / bot.py

"""Main bot script - bot.py
For the DigitalOcean Tutorial.
"""


import random
import time


from lxml.html import fromstring
import nltk
nltk.download('punkt')
import requests

from twitter import OAuth, Twitter


import credentials

tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')

oauth = OAuth(
       credentials.ACCESS_TOKEN,
       credentials.ACCESS_SECRET,
       credentials.CONSUMER_KEY,
       credentials.CONSUMER_SECRET
   )
t = Twitter(auth=oauth)

HEADERS = {
       'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                     ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
       }


def extract_paratext(paras):
   """Extracts text from <p> elements and returns a clean, tokenized random
   paragraph."""

   paras = [para.text_content() for para in paras if para.text_content()]
   para = random.choice(paras)
   return tokenizer.tokenize(para)


def extract_text(para):
   """Returns a sufficiently-large random text from a tokenized paragraph,
   if such text exists. Otherwise, returns None."""

   for _ in range(10):
       text = random.choice(para)
       if text and 60 < len(text) < 210:
           return text

   return None


def scrape_coursera():
   """Scrapes content from the Coursera blog."""
   url = 'https://blog.coursera.org'
   r = requests.get(url, headers=HEADERS)
   tree = fromstring(r.content)
   links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')

   for link in links:
       r = requests.get(link, headers=HEADERS)
       blog_tree = fromstring(r.content)
       paras = blog_tree.xpath('//div[@class="entry-content"]/p')
       para = extract_paratext(paras)
       text = extract_text(para)
       if not text:
           continue

       yield '"%s" %s' % (text, link)


def scrape_thenewstack():
   """Scrapes news from thenewstack.io"""

   r = requests.get('https://thenewstack.io', verify=False)

   tree = fromstring(r.content)
   links = tree.xpath('//div[@class="normalstory-box"]/header/h2/a/@href')

   for link in links:
       r = requests.get(link, verify=False)
       tree = fromstring(r.content)
       paras = tree.xpath('//div[@class="post-content"]/p')
       para = extract_paratext(paras)
       text = extract_text(para)
       if not text:
           continue

       yield '"%s" %s' % (text, link)


def main():
   """Encompasses the main loop of the bot."""
   print('Bot started.')
   news_funcs = ['scrape_coursera', 'scrape_thenewstack']
   news_iterators = []
   for func in news_funcs:
       news_iterators.append(globals()[func]())
   while True:
       for i, iterator in enumerate(news_iterators):
           try:
               tweet = next(iterator)
               t.statuses.update(status=tweet)
               print(tweet, end='\n')
               time.sleep(600)
           except StopIteration:
               news_iterators[i] = globals()[newsfuncs[i]]()


if __name__ == "__main__":
   main()

保存して `+ bot.py +`を終了します。

以下は、 `+ bot.py +`のサンプル実行です。

python3 bot.py

ボットがスクレイピングしたコンテンツを示す出力を、次のような形式で受け取ります。

Output[nltk_data] Downloading package punkt to /Users/binaryboy/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
---Bot started---

"Take the first step toward your career goals by building new skills." https://blog.coursera.org/career-stories-from-inside-coursera/

"Other speakers include Priyanka Sharma, director of cloud native alliances at GitLab and Dan Kohn, executive director of the Cloud Native Computing Foundation." https://thenewstack.io/cloud-native-live-twistlocks-virtual-conference/

"You can learn how to use the power of Python for data analysis with a series of courses covering fundamental theory and project-based learning." https://blog.coursera.org/unlock-the-power-of-data-with-python-university-of-michigan-offers-new-programming-specializations-on-coursera/

"“Real-user monitoring is really about trying to understand the underlying reasons, so you know, ‘who do I actually want to fly with?" https://thenewstack.io/how-raygun-co-founder-and-ceo-spun-gold-out-of-monitoring-agony/

ボットのサンプル実行後、ボットによってTwitterページに投稿されたプログラムによるツイートの完全なタイムラインが表示されます。 それは次のようになります。

image:https://assets.digitalocean.com/articles/TwitterPython/step5a.png [投稿されたプログラムによるツイート]

ご覧のとおり、ボットは、スクレイプされたブログのリンクを、各ブログからのランダムな引用をハイライトとしてツイートしています。 このフィードは、Courraとthenewstack.ioからのブログの引用を交互にツイートする情報フィードになりました。 Webからコンテンツを集約してTwitterに投稿するボットを構築しました。 さまざまなWebサイトにスクレイパーを追加することにより、このボットの範囲を希望どおりに広げることができます。ボットは、すべてのスクレイパーからのコンテンツをラウンドロビン方式で、希望する時間間隔でツイートします。

結論

このチュートリアルでは、Pythonを使用して基本的なTwitterボットを構築し、ボットがツイートするためにWebから一部のコンテンツをスクレイピングしました。 試すべきボットのアイデアはたくさんあります。ボットのユーティリティに関する独自のアイデアを実装することもできます。 TwitterのAPIが提供する多機能な機能を組み合わせて、より複雑なものを作成できます。 より洗練されたTwitterボットのバージョンについては、https://github.com/schedutron/chirps [chirps]をご覧ください。マルチスレッドなどの高度な概念を使用してボットに複数のことを同時に行わせるTwitterボットフレームワークです。 misheardlyのような、楽しいアイデアのボットもあります。 Twitterボットを作成するときに使用できる創造性に制限はありません。 ボットの実装に適した適切なAPIエンドポイントを見つけることが不可欠です。

最後に、ボットのエチケットまたは(「ボチケット」)は、次のボットを構築するときに留意することが重要です。 たとえば、ボットにリツイートが組み込まれている場合、ツイートのすべてのテキストをフィルターに通して、不正な言語を検出してからリツイートするようにします。 正規表現と自然言語処理を使用して、このような機能を実装できます。 また、スクレイピングするソースを探している間、あなたの判断に従って、誤った情報を広めるものを避けてください。 ボケットの詳細については、Joe Mayoによるhttp://geekswithblogs.net/WinAZ/archive/2016/03/30/botiquette.aspx [このブログ投稿]をご覧ください。

Related