visudoでsudoersを変更して、sudo権限を設定する
zabbixユーザーとsudo等々の権限周りでハマりました。
備忘録として開発環境で動作確認したのを残しておきます。
環境
MacOS High Sierra 10.13.1
Vagrant 2.0.1
CentOS 7.2.1511
かんたんなsudoersの知識
sudoとかの権限を設定しているのは、
/etc/sudoers
というファイルです。
ちなみに/etc
の下にsudoのつくファイルは以下でした。
$ ls -l /etc/ | grep sudo
-rw-r-----. 1 root root 1786 Sep 25 2012 sudo.conf -r--r----- 1 root root 4191 Jan 16 17:27 sudoers drwxr-x---. 2 root root 20 Jan 27 2016 sudoers.d -rw-r-----. 1 root root 3181 Jul 25 2013 sudo-ldap.conf
よく見ると、sudoersは440で書き込みできませんね。
普通には書き込みができないのがこのsudoersファイルです。
普通に書き込みしてしまって、シンタックスエラーがある状態で保存してしまうと、二度とrootを使えなくなったりする危険なファイルです。
なので、sudoersを編集する際にはシンタックスチェックをする、安全なvisudoというコマンドを使って編集をしていきます。
一般ユーザーを作成します
rootになっておく
$ sudo su -
まずは、現在のユーザー一覧を確認
$ ls -l /home/
合計 2 drwx------. 5 vagrant vagrant 4096 1月 12 10:52 vagrant
vagrantユーザーだけでした。
userを追加
$ useradd test-user
ユーザー追加されたのを確認
$ ll /home
total 0 drwx------ 2 test-user test-user 59 Jan 16 17:01 test-user drwx------. 3 vagrant vagrant 90 Jan 27 2016 vagrant
test-userが作成されました。
test-userのパスワードを設定(一応)
$ passwd test-user
Changing password for user test-user. New password: Retype new password: passwd: all authentication tokens updated successfully.
パスワード設定完了。
権限確認
test-userにログイン
$ su test-user
$ whoami
test-user
test-userにログインできました。
sudoが必要なコマンドを実行してみます
$ yum install -y git
Loaded plugins: fastestmirror You need to be root to perform this command.
rootじゃないとできないみたいですね。
sudoをつけてみます。
$ sudo yum install -y git
We trust you have received the usual lecture from the local System Administrator. It usually boils down to these three things: #1) Respect the privacy of others. #2) Think before you type. #3) With great power comes great responsibility. [sudo] password for test-user:
やはり、パスワードがないとだめですね〜
これは当然ながらtest-userを作った管理者は知っていますが。。。
sudoers権限をいじります
rootに戻ります
$ exit
sudoersをいじります
$ visudo
以下の行をを一番下に追加します。
test-user ALL=(root) yum
test-userに root権限でのyumの使用を許可します。という意味です。
/bin/yumじゃなくていいのかな?
yumのオプションは何でも使えるのかな?
試しにやってみます。
編集を抜けると
visudo: >>> /etc/sudoers: syntax error near line 121 <<< What now? Options are: (e)dit sudoers file again e(x)it without saving changes to sudoers file (Q)uit and save changes to sudoers file (DANGER!) What now?
と、
何も考えずにQをやってしまったが最後、二度とsudoを使えなくなってしまいました。
rootにログインすることも叶わなかった。。。
VM立ち上げ直した。。。
これ本番でやったら偉いことになります。
めのまえがまっくらになった!状態になります。
所持金がなくなります。
そんな事故がないために、単にviだけでは編集できず、専用のsyntaxチェックをしてくれるvisudoを使うんですね~
さて、もう一度vagranをdestroyしてupして、visudoまでの操作を行います。
$ visudo
以下のように追加
test-user ALL=(root) NOPASSWD: /bin/yum
:wqでちゃんと正常に抜けられました。
動作確認
test-userにログイン
$ su test-user
権限を確かめる
$ sudo yum install -y git
->OK!
$ sudo yum history
→正常に表示されます。
yumのコマンドなら全部使えるっぽい。
権限をもう少し絞ってみます。
権限変更
とりあえず/bin/yumが使えることがわかりました。
オプション等々、どこまでsudoersファイルで制限できるのでしょうか。
試してみます。
rootになる
$ exit
$ visudo
一番下の行を以下の設定に変更
test-user ALL=(root) NOPASSWD: /bin/yum install -y tig
test-userになる
$ su test-user
確かめる
$ sudo yum install -y tig
出来ました。
他のコマンドは使えないのか確認します。
$ sudo yum install -y tree
ダメでした。パスワードを求められてしまいます。
全部決め打ちでroot権限を与えることもできるようですね。
どこまで制限できるのか
検証してみます。
$ visudo
次のように設定
test-user ALL=(root) NOPASSWD: /bin/yum install
期待する動作は、これでyum installなら何でも使えるけど、他のyumコマンドは使えない挙動!
試してみます
$ su test-user
$ sudo yum install -y tree
↓
なんかパスワード求められた。。。
なんかダメみたいだ。
なので、方法としては、
完全に決め打ちのコマンドを一つずつ書くか、
オプションは指定しないで、実行ファイルのパスだけを書くか。
のどちらかっぽい。
コマンドの処理の仕方とかもっと深く知れば「はいはい、そりゃそうだ」って言えるようになる気がする。
けど今は一つ一つ動作を検証してみて、こういう挙動なのだとわかりました!頑張った!
あと実はファイルパスとディレクトリの権限等のこともハマったので、次回整理してまとめておきたいです。
python3でstrからdictに変換する
import ast str = "{'name':'Taro', 'hieght':170}" type(str) => <class 'str'> dict = ast.literal_eval(str) type(dict) => <class 'dict'>
他の記事でast.literal_dict(str)
となっていたのですが、
AttributeError: module 'ast' has no attribute 'literal_dict'
とエラーになってしまったので、調べてみたら、literal_dictではなく、literal_evalでした。
AWS EMRを使ったhiveのチュートリアル
やりたいこと
以下のような3つの項目を持ったjsonファイルがあります。
id, cookie, date
基本的にはidはcookieと一対一の関係にありますが、たまにあるcookieに対して同じidが振られていることがあります。 つまり、cookieは完全にユニークですが、idには重複があります。 困りました。
この重複をなくして、idとcookieともに完全にユニークなデータセットにしたいと思います。 idが同じオブジェクトあったときは、dateを参照して新しい方のcookieを残して古い方のcookieは無視します。 同じ日に一つのidに対して異なるcookieが生成されることはないものとします。
データはS3から読み込んでS3に保存します。 入力 s3://hive-00001111-ap-northeast-1/Cookie_origin/の下に、複数ファイルに別れたtsvファイルがあります。 出力 s3://hive-00001111-ap-northeast-1/Cookie_unique/以下に保存したいです。
データセット生成
https://www.json-generator.com/ このサイトで以下のような条件で100レコード分のjsonファイルを生成して、indentをcompactでダウンロードします。
[ '{{repeat(100, 100)}}', { _id: '{{objectId()}}', cookie: '{{guid()}}', date: '{{date(new Date(1000, 0, 1), new Date(), "YYYYMMdd")}}' } ]
generated.json
という名前でダウンロードされました。
若干テキストエディタで整形します。
まずは、先頭と最後の[]を削除します。
次に
},{
を
} {
で置換します。これで、いい感じの元データができました。 試しに先頭の5行だけ抜き出してみます。
{"_id":"5a02dcbb94b8be7f1a0fe41e","cookie":"c8be7285-608c-4158-86c6-0c8e03a5a8d3","date":20160720} {"_id":"5a02dcbbec03abdc3585ba76","cookie":"b744804e-0423-4283-995a-843ce861f305","date":20130423} {"_id":"5a02dcbb47fe699b5d4f1b4f","cookie":"1fbec6e8-b6a7-41f7-99a2-708e04f86ab8","date":20170912} {"_id":"5a02dcbb5b3d47ca9c229706","cookie":"31216342-1d61-4f2b-8315-755b163ee225","date":20120325} {"_id":"5a02dcbbfeb00508901f7261","cookie":"0415a1e9-19c8-4a77-a4c6-7aa85fff733a","date":20140928}
こんな感じです。 このファイルから5件だけidのvalueをコピーして他の行のidのvalueにしておきます。
s3の構成
s3のファイル構成は以下のようにします。
S3 └── hive-00001111-ap-northeast-1 ├── Cookie_origin │ └── generated.json ├── Cookie_unique └── src └── uniquify_id.q
generated.jsonはダウンロードしたファイルです。 uniquify_id.qは後ほど説明します。
HiveQL
HiveはHiveQLというSQLによく似たクエリを使っています。 そんなにSQLに詳しくないですが、SQLでできる基本的なことはほとんどできるっぽいです。
uniquify_id.q
-- -------------------------------------------------- -- 使用するテーブルを作成 -- -------------------------------------------------- CREATE EXTERNAL TABLE IF NOT EXISTS id_origin(line STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n' LOCATION 's3://hive-00001111-ap-northeast-1/Cookie_origin'; CREATE EXTERNAL TABLE IF NOT EXISTS id_unique ( id STRING, cookie STRING, get_date STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n' LOCATION 's3://hive-00001111-ap-northeast-1/Cookie_unique'; -- -------------------------------------------------- -- Jsonをパースする -- -------------------------------------------------- INSERT INTO TABLE id_unique SELECT json_data.* FROM id_origin LATERAL VIEW json_tuple(id_origin.line, '_id','cookie', 'date') json_data AS id, cookie, get_date; -- -------------------------------------------------- -- idとcookieを一対一にする。 -- -------------------------------------------------- INSERT OVERWRITE TABLE id_unique SELECT A.id, A.cookie, A.get_date FROM id_unique AS A INNER JOIN (SELECT id,MAX(get_date) AS NEWEST FROM id_unique GROUP BY id) AS B ON A.id = B.id AND A.get_date = B.NEWEST;
細かいHiveQLの書き方は以下のサイトをとても参考にさせていただきました。 http://www.ne.jp/asahi/hishidama/home/tech/apache/hive/ql.html
AWS EMR
クラスター作成
ここからEMRに操作です。
まずはコンソールでEMRを選択します。
以下のように設定します。 基本はデフォルトのままで。 クラスター名は適当。 EC2キーペアはいつもの奴を選択。 クラスターを作成。
ステップ追加
続いてステップを追加していきます。 ステップタブから、「ステップの追加」
ステップタイプはHiveプログラム スクリプト場所は、s3://hive-00001111-ap-northeast-1/src/uniquify_id.q を指定して、作成。
しばらく待ちます。
今回のデータ量だと1,2分待てば良さそうです。 しばらく待ってから更新をかけます。 ステータスが完了になっていたら成功です。
確認
S3の保存先を確認してみます。 Cookie_uniqueフォルダと同じ階層にCookie_unique_$folder$というファイルができていますが、これはhiveのテーブルとCookie_unique/のデータを結びつけているものです。特に理由がなければそのままにしておくのが吉な気がします。
Cookie_uniqueの中に000000_0というファイルが生成されています。これが欲しかったデータです。 ダウンロードして確認してみます。 idが同一のデータを5ペア作ったので、95行になっているか確認します。
$ wc 000000_0
95 285 6745 000000_0
うまくいってそうです。
これにてユニーク化終了です。お疲れ様でした。
なんかうまくいかないってときは、ターミナル等から直接操作もできます。
クラスター > (クラスターを選択する) > ハードウェア > ノードタイプがMASTERのやつを選択
パブリックIPアドレスから普通にsshでログインできます。 ユーザー名はhadoopでログインします。(ec2-userにしちゃうとhiveが使えない)
こんなのが表示されればOKです。
`$ hive' でhiveに入れます。 ここからはMySQLとかと同じ要領でできます。
AWSのEMRを使ってHiveの基本的な使い方を確認しておく備忘録
Hiveとは?
Hiveとは?
Hive(ハイブ)とは、オープンソースの大規模分散計算フレームワークHadoop上で動作するデータウェアハウス(DWH)向けのプロダクトです。
Hiveとは | クラウド・データセンター用語集/IDCフロンティア
とあります。
大規模なデータ処理をするときに使うMySQLみたいなやつ。...だと勝手に思ってます。
実際HiveのためのHiveQLという言語は、SQLによく似ています。
Hiveを起動するまで
AWSネジメントコンソールからEMRを作成。
マスターノードのEC2インスタンスのipを調べて、sshでログイン。
ユーザー名はhadoopでログインします。
$ ssh -i path/to/your/ssh_key hadoop@[ip address]
ログインしてから$ hive
でHiveを使えるようになっています。
Hive
データベース一覧を表示
まずはデータベースを確認してみる。
SHOW DATABASES;
データベース作成
companyというデータベースを作成する。
CREATE DATABASE company;
作成されていることを確認します。
SHOW DATABASES;
今回、Hiveで扱いたいのは、EMPLOYEEという名前のファイルがjson形式でS3に保存してあるとしましょう。
保存場所はs3://mybucket/EMPLOYEE
中身は、以下です。
{"name":"tanaka","age":24,"section":"sales"} {"name":"yamada","age":45,"section":"engineer"} {"name":"yamamoto","age":34,"section":"engineer"} {"name":"inoue","age":33,"section":"sales"} {"name":"komori","age":22,"section":"engineer"} {"name":"takahashi","age":40,"section":"admin"}
テーブルを作成
Hiveでデータの挿入は、1行ずつ入れるみたいなことができないらしい。
ファイルを全部読み込みバルクインサートっていう方法でしかインポートできないって書いてあった気がしました。
なので、予めファイルを作っておいて、それを読み込む形にしておきます。
と、データのインポートの前に、テーブルを定義しておきます。
データの流れとして、
1. カラムが一つのテーブルを作成し、1行1jsonとして格納します
2. jsonをパースして、3つのカラムに分けて新しい別のテーブルに格納します。
json格納用の一時テーブル
CREATE TABLE emp_line( line STRING );
最終的に扱いたいテーブルをつくります
CREATE TABLE employee ( name STRING, age INT, section STRING );
テーブル一覧を表示
テーブルが作成されているか一覧で見てみましょう。
SHOW TABLES;
テーブルの構造を表示
カラム等の定義を確認することもできます。
DESC employee;
jsonファイルを事前に用意
s3://bucket-name/path/to/your/file/employee.json
{"name":"tanaka","age":24,"section":"sales"} {"name":"yamada","age":45,"section":"engineer"} {"name":"yamamoto","age":34,"section":"engineer"} {"name":"inoue","age":33,"section":"sales"} {"name":"komori","age"22:,"section":"engineer"} {"name":"takahashi","age":40,"section":"admin"}
s3からデータをロード
データをロードして追加するなら以下
LOAD DATA INPATH 's3://mybucket/EMPLOYEE'
INTO TABLE emp_line;
追加ではなく、上書きするなら、OVERWRITEをつけます。
LOAD DATA INPATH 's3://mybucket/EMPLOYEE'
OVERWRITE INTO TABLE emp_line;
この状態だと、emp_lineテーブルに1カラム1jsonとして格納されている。
SELECT * FROM emp_line;
をすると
OK {"name":"tanaka","age":24,"section":"sales"} {"name":"yamada","age":45,"section":"engineer"} {"name":"yamamoto","age":34,"section":"engineer"} {"name":"inoue","age":33,"section":"sales"} {"name":"komori","age"22:,"section":"engineer"} {"name":"takahashi","age":40,"section":"admin"} Time taken: 1.4 seconds, Fetched: 6 row(s)
となる。
シンプルなjsonをパース
jsonをパースするには、次のようにします。
SELECT emp.* FROM emp_line LATERAL VIEW json_tuple( emp_line.line, 'name', 'age', 'section' ) emp AS name, age, section;
とすると、
OK tanaka 24 sales yamada 45 engineer yamamoto 34 engineer inoue 33 sales komori 22 engineer takahashi 40 admin Time taken: 0.092 seconds, Fetched: 6 row(s)
となる。これを別のテーブルに格納すれば完成。
employee
テーブルに格納するには
INSERT INTO TABLE employee SELECT emp.* FROM emp_line LATERAL VIEW json_tuple( emp_line.line, 'name', 'age', 'section' ) emp AS name, age, section;
と、SELECTの結果をINSERT INTO TABLE [table名]として新たに代入するだけです。
ネストしたjsonをパース
余談ですが、jsonがネストしているパターンを考えてみます。
ネストしているjsonを用意する
{"name":{"str":"tanaka"},"age":{"int":24},"section":{"str":"sales"}} {"name":{"str":"yamada"},"age":{"int":30},"section":{"str":"engineer"}} {"name":{"str":"katou"},"age":{"int":50},"section":{"str":"admin"}} {"name":{"str":"yamamoto"},"age":{"int":44},"section":{"str":"sales"}} {"name":{"str":"suzuki"},"age":{"int":29},"section":{"str":"engineer"}} {"name":{"str":"hirose"},"age":{"int":48},"section":{"str":"sales"}}
シンプルなjsonと同じように記述する
SELECT data.* FROM emp_line LATERAL VIEW json_tuple( emp_line.line, 'name', 'age', 'section', ) data AS name, age, section;
すると
OK {"str":"tanaka"} {"int":24} {"str":"sales"} . . .
となり、余計な文字が残ってしまう。
もう一つネストを外したい。
参考: https://qiita.com/unksato/items/42405305c28e5a788cd7
literal viewを連続で使う。
SELECT data.* FROM emp_line LATERAL VIEW json_tuple( emp_line.line, 'name', 'age', 'section' ) json_data AS name, age, section lateral view json_tuple( json_data.name, 'str' ) data as name lateral view json_tuple( json_data.age, 'int' ) data as age lateral view json_tuple( json_data.section, 'str' ) data as section;
これで正しく出力される。
勝手に意味を補ってみる。
SELECT data.* FROM emp_line[(後に作られる仮の)dataテーブルのすべてのカラムを選択][元になるのはemp_lineテーブル] LATERAL VIEW json_tuple( emp_line.line,[emp_lineテーブルのlineカラムをjsonパース] 'name',[nameがキーのものを] 'age',[ageがキーのものを] 'section',[sectionがキーのものを] ) json_data AS name, age, section[仮のjson_dataテーブルにname,age,sectionというカラムで生成する。] lateral view json_tuple( json_data.name,[json_dateテーブルのnameカラムをjsonパース] 'str'[sがキーのものを] ) data as name[仮のdataテーブルにnameというカラムで生成する。] [以下重複] lateral view json_tuple( json_data.age, 'int' ) data as ttl lateral view json_tuple( json_data.section, 'str' ) data as section;
ちなみにカラム名にdateを使うと、なんかだめっぽい。
整形先のテーブルを作成
create table emp_all( name string, age int, section string, );
データのインサート
insert into table emp_all SELECT data.* FROM emp_line LATERAL VIEW json_tuple( emp_line.line, 'name', 'age', 'section', ) data AS name, age, section;
重複データを無視してSELECT
すべてのカラムが重複するデータを削除して表示する。
select distinct * from emp_all;
これで、同一データはなくして軽くできる。
こんな感じで基本的な操作はMySQLで使えるものはほとんど使えるっぽい。
ビットコインの自動売買プログラムを作る①APIいじってみる〜
bitflyerのAPIを使ってビットコインの売買が結構かんたんにできちゃいます。
以下のページから使いたいAPIを探します。 全部日本語で書いてあるので、嬉しいですね。
こちらでサンプルコードが載っているので、ほぼまんまコピペで簡単にAPIを使えちゃえます。
これは至れり尽くせり。
sendchildorder.rb
require "net/http" require "uri" require "openssl" require "./key" key = API_KEY secret = API_SECRET timestamp = Time.now.to_i.to_s method = "POST" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/sendchildorder" body = '{ "product_code": "BTC_JPY", "child_order_type": "LIMIT", "side": "BUY", "price": 740000, "size": 0.001, "minute_to_expire":1200 , "time_in_force": "GTC" }' text = timestamp + method + uri.request_uri + body sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Post.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, "Content-Type" => "application/json" }); options.body = body https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true response = https.request(options) puts response.body
key.rb
API_KEY = "XXXXXXXXXX" API_SECRET = "XXXXXXXXXXXXXXXXXXXX"
これで740,000円で買い注文が出せました。
調整する部分は
"product_code": "BTC_JPY", # BTCとJPY "child_order_type": "LIMIT", # 指値注文 "side": "BUY", # 買い注文 "price": 740000, # 740,000円 "size": 0.001, # 0.001BTC "minute_to_expire":1200 , # 有効期限 1200分 "time_in_force": "GTC"
の部分だけです。
これをうまいことチューニングするだけで果たして儲かるのでしょうか〜
次回は、価格がどんな風に動いているのか、できるだけ細かくログを取ってみます
rubyとseleniumでTwitterに自動ログインする。〜リベンジ編
SeleniumでTwitterの自動ブラウザ操作を行っていきたいです。
以前設定していたのですが、しばらくしてみると、そのコードでは対応できなくなっていました。
require 'selenium-webdriver' driver = Selenium::WebDriver.for :firefox driver.get "https://twitter.com/login"
ここまでで以下の画面になります。(firefoxのdriverなどの設定が別途必要だった気がしますが)
このメールアドレスとパスワードに値を自動で挿入してログインボタンをクリックしてログインしたいと思います。
まずは、フォームから。
開発者ツールで、この要素を見てみると、次のようになっています。
要素は
<input class="js-username-field email-input js-initial-focus" name="session[username_or_email]" autocomplete="on" value="" placeholder="電話番号/メールアドレス/ユーザー名" type="text">
です。
ここで、seleniumの書き方に従って、 (classを指定する方法は確か失敗した気がします。。。もしくは一意なclassがなかったか。)
driver.find_element(:name, 'session[username_or_email')..send_key "user_name"
としても、
Selenium::WebDriver::Error::ElementNotInteractableError: Element is not visible
となり、エラーになってしまいました。
qiitaでやってみたらうまく行ったので、TwitterのCSSの問題なのか、それとも単にハッシュみたいな書き方に対応していないのか。
と思ったら、以前書いてたコードでは普通に
driver.find_element(:name, "session[password]").send_key "password"
のような形で書いていたので、おそらくCSS側の問題ですね。
解決策として、xpathを指定してあげたら、どうもうまくいきました。
xpathは開発者ツールで秒速で見つけられます。
我らがfirefoxですね。
...おっと、firefoxではできませんでした。(探せば見つかるはずだけどめんどい)
ということで、我らがchromeで
与沢翼も裸足で逃げ出すくらい秒速でした。
driver.find_element(:xpath, '//*[@id="page-container"]/div/div[1]/form/fieldset/div[1]/input').send_key "user_name" driver.find_element(:xpath, '//*[@id="page-container"]/div/div[1]/form/fieldset/div[2]/input').send_key "password" driver.find_element(:xpath, '//*[@id="page-container"]/div/div[1]/form/div[2]/button').click
こんな感じでログイン成功しました。
あとは煮るなり焼くなり好きにして状態ですね。
自動ファボ&RTのコード下の記事にあります。
SeleniumとRubyでTwitterの複数アカウントを自動ファボ&RT
背景
自分の趣味というか、ちょっとしたプロジェクトでTwitterを運営していて、特定のワードで検索されたときに上位に表示させたいなーと思うことがありました。
一つの方法が、ツイートを頻繁にするということで、それはbotで普通に解決できました。これはノンプログラマーでもできますね
bot化したのはだいぶ前だったので、正確には覚えていませんが、確かココらへんを使ってた思い出があります。というか今も使ってるはずですが忘れて確認するのが面倒くさいだけです。
楽ボッツ - 初心者向き twitter bot(ボット)サービス
ほんといいサービス達です。
で、Twitterで検索したときは、この画面がまず出るわけです。
検索ワードによって少々構成が変わることもあったりはするみたいですが、基本こんな感じで、まず一番に表示されるのは話題のツイートです。
ここではツイートまたはユーザーが表示されます。
僕の独自の調査では、この表示されるのに有効な要素は、
- フォロワー数
- Tweetのファボ数
- TweetのRT数
ですね。普通か。
ということで、ファボ&RT数を増やしたい。
それも自分の内々のアカウント群で。
どうやら調べてみると、なんとかマティックっていう怪しい有料のツールはあるみたいですが、それはなんか使いたくなかったので、自作してそれっぽいことをすることに。
いや〜成長しましたね〜
2年前の僕は必死にそういうサービスがないか検索しまくるのが関の山でした。
ということで、余談おしまいです。
APIは使えないのか?
TwitterにはもちろんAPIがありますが、ざっと調べた感じ、自動ファボはできなかったような気がします…
前はできたみたいなんですけどね
もしかしたら普通にできたかも。
Seleniumとかスクレイピングの練習ってことで!
コード
ちょっと前に実装したので、driverのinstallのあたりで若干苦戦した気もしますが、忘れてしまいました。
基本的には実際にTwitterのページを開いて開発者ツールでHTMLコード見て、ゴリゴリにチューニングしてどうにかこうにか動くって感じです。
結構Twitterは罠が多いです。ログインのところとか結構罠でした。
そういう理由から、チューニングしきれず、ちょいちょいエラーになりそうなのを強引にその後の処理を捨ててるので、精度はそこまで高くないです。
回り続けることを優先しています。
# execute `$ watch -n 1800 ruby path/to/this/project/auto_favo_RT_with_selenium.rb` to run every 30 minutes require "selenium-webdriver" user_names = [ "account1", "account2", "account3" ] for user_name in user_names do driver = Selenium::WebDriver.for :firefox driver.get "https://twitter.com" # ログインする sleep 1 begin driver.find_element(:class, "js-login").click driver.find_element(:name, "session[username_or_email]").send_key "#{user_name}" driver.find_element(:name, "session[password]").send_key "password" #パスワードは全部同じとして driver.find_element(:class, "js-submit").click rescue driver.quit puts "login error" next end puts "login with #{user_name}" # 検索してファボ&RT driver.get "https://twitter.com/search?f=tweets&vertical=default&q=ANYWORD&src=typd" for i in 0..10 do begin driver.find_elements(:class, "js-actionFavorite")[i*2].click driver.find_elements(:class, "js-actionRetweet")[i*2].click driver.find_element(:class, "RetweetDialog-retweetActionLabel").click rescue puts "Error: in #{i}" break end sleep 2 end driver.quit end
同じコードですがgithubに上げときます。 github.com
これをMacのターミナルから実行させときます。
$ watch -n 1800 ruby path/to/this/project/auto_favo_RT_with_selenium.rb
これだと1800秒ごと、30分ごとに実行されます。
これは自分のbotのツイート数と併せてこのくらいの感覚でいいなって思って設定しました。
30分ごとに10個ずつふぁぼっていくので、そのくらいのペースということです。
重複しそうになったら、そこでそのループは終了します。
では、悪用しないで楽しいTwitterライフを送りましょう!!!
課題
一つだけ問題点があって、普通にパソコンを使っていると、30分毎にお気にFirefoxが出現して、最前面でブラウザ操作を行っていくことです。
ちょっとうっとうしい。
次のステップとしては、フォローアンフォローも自動化していきたいです。
あとAWSとか使ってやりたい。
ブラウザ操作なんて不細工なことはしたくないな……