まえがき
今では多くの人がInstagram(以下instaと呼ぶ)を使用しています。誰かがそこでアルバムを収集し、誰かが売り、誰かが買い、そして私はそこで怠け者です。 私はいつも私の友人、クラスメート、同僚、インスタがどのようにやっているのか興味がありました。 彼はそこで何が新しくなったかを知りたかった-彼は入って、テープをめくって、興味のあるものすべてが残っているのを見た...しかし! 何らかの理由で、私は常にすべての投稿を好きにする必要がありました(理由は説明できませんが、そのようなこと)。 想像してみてください。私は一週間そこに行ったことがなく、座っていて、毎週のプールが好きで、200以上のサブスクリプションがある場合、これは一般に地獄です。
アクティブなアクション
その結果、普通の人と同じように、私は怠けすぎてすべてを好きにならず、得点しました。 すべてがうまくいくように思えたので、私は無用な同類に多くの時間を費やすことを止めましたが、私の良心は食べました。 加入者は私の王室のように気分が悪い、彼らは悲しくて何とか何とかだと理解しました...一般的に、simpleりの問題を解決し、おそらく誰かを助けることができるシンプルで簡単なものを書く必要があることが決定されました。 pythonについて、またセレンを使用してテストアプリケーションを冷却する方法またはクローラーとして使用する方法について、友人から多くのことを聞きました。 pythonとseleniumをファントムjsと組み合わせて使用することが決定されました。 それ以前は、これらのテクノロジーにまったく慣れていませんでした。
なぜセレンとファントム?
ここではすべてが非常に簡単です。 instagramのクライアント側はリアクティブで記述されているため、ページがレンダリングされた後にのみデータをプルできます。 なぜなら セレンはブラウザのアクションを自動化するだけであり、ファントムjsは表示せずにすべてを実行するのに役立ちます。使用することにしました。 将来的には、ファントムjsはかなり遅いため、Chromeにはヘッドレスオプションがあり、「ヘッドレス」ブラウザとして使用できるため、ファントムjsを放棄することにしました。
なぜpython?
私は多くのことを聞いて、この言語はビッグデータを扱うのに最適であると読みました。ここから、すべてのデータ(解析、ソート、比較、フォーマットなど)を扱うのが便利だと結論付けました。また、彼のために自分のミニライブラリを書くのが便利で迅速であることをどこかで読みました(そして、これはボットが可能な限り普遍的にするために必要なものです)。 すべてを検討した後、私はpython3で停止することにしました(それ以前は、プロジェクトの一部は既にpython2およびpython3で実行できるように作成されていました)。
ボットのライブラリ開発
プロセス全体を説明するのはばかげているので、最も興味深い点に焦点を当てましょう。
ログイン
ボットは、許可が必要な同じアクションの多数の繰り返しであるため、このプロセスで何かを考え出す必要がありました。 フォームを介してログインするたびに非常に疑わしいため、Cookieをプルして認証に使用しようとすることが決定されました。
instagramはこれで簡単であることが判明しました(しかし、mail ruは私に大きな頭痛を与えました):import pickle import time import tempfile import os import selenium.common.exceptions as excp def auth_with_cookies(browser, logger, login, cookie_path=tempfile.gettempdir()): """ Authenticate to instagram.com with cookies :param browser: WebDriver :param logger: :param login: :param cookie_path: :return: """ logger.save_screen_shot(browser, 'login.png') try: logger.log('Trying to auth with cookies.') cookies = pickle.load(open(os.path.join(cookie_path, login + '.pkl'), "rb")) for cookie in cookies: browser.add_cookie(cookie) browser.refresh() if check_if_user_authenticated(browser): logger.log("Successful authorization with cookies.") return True except: pass logger.log("Unsuccessful authorization with cookies.") return False def auth_with_credentials(browser, logger, login, password, cookie_path=tempfile.gettempdir()): logger.log('Trying to auth with credentials.') login_field = browser.find_element_by_name("username") login_field.clear() logger.log("--->AuthWithCreds: filling username.") login_field.send_keys(login) password_field = browser.find_element_by_name("password") password_field.clear() logger.log("--->AuthWithCreds: filling password.") password_field.send_keys(password) submit = browser.find_element_by_css_selector("form button") logger.log("--->AuthWithCreds: submitting login form.") submit.submit() time.sleep(3) logger.log("--->AuthWithCreds: saving cookies.") pickle.dump([browser.get_cookie('sessionid')], open(os.path.join(cookie_path, login + '.pkl'), "wb")) if check_if_user_authenticated(browser): logger.log("Successful authorization with credentials.") return True logger.log("Unsuccessful authorization with credentials.") return False def check_if_user_authenticated(browser): try: browser.find_element_by_css_selector(".coreSpriteDesktopNavProfile") return True except excp.NoSuchElementException: return False
Cookieによる認証が失敗した場合、ログイン/パスワードで認証し、Cookieを保存して、将来的には標準スキームとして使用します。
#TODO:
ニュースフィード
なぜなら まず第一に、私は自分自身のためにこれを書いた、私は常にニュースフィードが排出されていたことは私にとって興味深いものでした。 最初は、すべてがシンプルで、上から最後に処理されたポストまでスクロールし、ポストのWeb要素が配列に入力され、後ろの要素がオンになり、すべてが、以前に作成された配列にあるポストのWeb要素を介してレイアウトされたリターンパスに似ています。 すべてが私が望んでいた通りに機能することを嬉しく思いましたが、約2か月後に「月は山羊座」になり、私のボットは愚かに動作しなくなりました。 可能な限りすべてをチェックしました。さまざまなWebドライバーで、視覚的に何も変わっていませんが、何も機能しません。 一般に、私は約3日間問題を探して殺しました。 すべてが非常にシンプルであることが判明しました。以前は、ボットがスクロールされた投稿を通過すると、彼はオブジェクトを配列から取り出し、投稿にスクロールし(人間の行動を模倣します)、そこで「いいね」ボタンを見つけ、それを押し続けました。 これで、Instagramはhtmlマークアップに保存することを決定しました。構造の5番目がユーザーに対してアクティブであり、前の4と次の4、残りのすべてがhtmlから削除された9ポストのみです。 リンクによって配列に似ている必要があるそれらの投稿を収集して問題を解決する必要がありました。次に、スクロールアップ(愚かに上に)するときに、以前に収集された配列で現在の投稿を探します。
その中毒..for post in progress: real_time_posts = br.find_elements_by_tag_name('article') post_link = post.get('pl') filtered_posts = [p for p in real_time_posts if self._get_feed_post_link(p) == post_link] if filtered_posts.__len__(): real_post = filtered_posts.pop() # scroll to real post in markup heart = real_post.find_element_by_css_selector('div:nth-child(3) section a:first-child') self.browser.execute_script("return arguments[0].scrollIntoView(false);", heart) # getting need to process elements author = real_post.find_element_by_css_selector('div:first-child .notranslate').text heart_classes = heart.find_element_by_css_selector('span').get_attribute('class') # check restrictions is_not_liked = 'coreSpriteHeartOpen' in heart_classes is_mine = author == login need_to_exclude = author in exclude if is_mine or not is_not_liked: self.post_skipped += 1 pass elif need_to_exclude: self.post_skipped_excluded += 1 pass else: # like this post time.sleep(.3) heart.click() time.sleep(.7) self.db.likes_increment() self.post_liked += 1 log = '---> liked @{} post {}'.format(author, post_link) self.logger.log_to_file(log)
勝利!
アクション制限
多くの注目を集めないために、ボットにいくつかの制限を加える必要があります。 これらの制限を順守するには、どこかで実行されたアクションのカウンターを保存する必要があります。 Sqliteは、すべての内部情報(迅速、便利、ローカル)のリポジトリとして選択されました。 ライブラリで、データベースで作業するための小さなモジュールを作成しました。また、将来のリリースのために移行を追加しました。 すべてのいいね/フォローは、作成された時間とともにデータベースに保存され、その後、1日あたりのいいね/フォロー/現在の時間がカウントされ、このデータに基づいて、他の誰かが好きかフォローできるかが決定されます。 制限は依然としてライブラリに厳密に登録されているため、構成可能にする必要があります。開発の分派
ボットのライブラリが書かれている間に、数字の問題が頭の中に現れました。 投稿のコンテキストでのユーザーの好み、ビュー、コメントの数や要約が興味深いものになりました。 関心を満たすために、ライブラリの小さなクラスが作成されました。これは、プライベートapi instagramを介してすべての利用可能な統計を(許可なしで)収集し、ユーザーに提供しました。
非表示のテキスト+-- https://instagram.com/al_kricha/ --------------------------+ | counter | value | +------------------------------+-------------------------------+ | followed | 402 | | posts | 397 | | comments | 1602 | | likes | 20429 | | following | 211 | | video views | 6138 | | | +--------- https://github.com/aLkRicha/insta_browser ----------+ +--------------------------------------------------------------+ | top liked posts | +--------------------------------------------------------------+ | https://instagram.com/p/BVIUvMkj1RV/ - 139 likes | | https://instagram.com/p/BTzJ38-DkUT/ - 132 likes | | https://instagram.com/p/BI8rgr-gXKg/ - 129 likes | | https://instagram.com/p/BW-I6o6DBjm/ - 119 likes | | https://instagram.com/p/BM4_XSoFhck/ - 118 likes | | https://instagram.com/p/BJVm3KIA-Vj/ - 117 likes | | https://instagram.com/p/BIhuQaCgRxI/ - 113 likes | | https://instagram.com/p/BM6XgB2l_r7/ - 112 likes | | https://instagram.com/p/BMHiRNUlHvh/ - 112 likes | | https://instagram.com/p/BLmMEwjlElP/ - 111 likes | +--------------------------------------------------------------+
そのようなデータを持っているので、私の友人と私( txwkx )はそれらを視覚化し、 instameter.meを作成しました。これは、開いているinstagramアカウントの「概要」を確認できる小さなサービスです。
例
ボットは何ができますか?
今日、ボットはどれだけ望んでいるかを知りませんが、それでも、主要なアクションを実行します。
- 彼は、好まない最後のフィードまでニュースフィードが好きです。
- 指定された数の投稿のいいねタグ
- 指定した数の投稿の場所が好き
- 設定をオンにすると、場所/タグの投稿からユーザーを自動フォローしますが、連続してではなく、潜在的に購読者になる可能性のあるユーザーのみをフォローします
- ユーザー統計を収集します
- 完了したアクションの時間に関する統計を保持します
今後何をしたいですか?
- ±意味のあるコメントを書く
- 不要なアカウントから退会する
- 新しくフォローした人のいくつかの投稿のように
- ニュースフィードアルゴリズムを書き換える
- 複数のアカウントを比較する
おわりに
まだやるべきことが多くあり、最適化され、書き直されています。 他の目的のためにツールをいつでも効果的に使用できます。 怠azineは間違いなく進歩のエンジンです。 私のボットが仕事や趣味で誰かを助けることを願っています。 pypiパッケージを含むリポジトリは、初心者の自動化ツールに役立ちます。 サンプルを含むリポジトリは、SMMに役立ちます。 ご清聴ありがとうございました。
参照資料
- insta_browser-ボットの中心である私のミニライブラリ
- insta_bot-リポジトリの例、ボット自体(この形式では使用します)
- instameter -instagramアカウントの統計を取るためのプロジェクト