YiiChina 自动签到脚本
依赖
- Ruby 2.1+
- Bundler
- Nokogiri
- HTTParty
用法
# bundle install
# bundle exec ruby ./registration.rb <username> <password>
- 调用时,用户名和密码也可以通过系统变量传递,例如:
# USERNAME=<username> PASSWORD=<password> bundle exec ruby ./registration.rb
source 'https://rubygems.org/' | |
gem 'httparty', '~> 0.13.7' | |
gem 'nokogiri', '~> 1.6.6.2' |
require 'logger' | |
require 'nokogiri' | |
require 'httparty' | |
class Object | |
def blank? | |
respond_to?(:empty?) ? !!empty? : !self | |
end | |
def present? | |
!blank? | |
end | |
def presence | |
self if present? | |
end | |
end | |
class YiiChina | |
include HTTParty | |
base_uri 'www.yiichina.com' | |
def initialize(username:, password:) | |
@csrf_token = nil | |
@identity_cookie = nil | |
@username, @password = username, password | |
@user_agent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0'.freeze | |
raise ArgumentError.new('User identity isn\'t correct') if @username.blank? || @password.blank? | |
end | |
def login | |
raise 'Already logged in' unless @identity_cookie.nil? | |
login_get_resp = self.class.get('/login', headers: { 'User-Agent' => @user_agent }) | |
login_form_html = Nokogiri::HTML(login_get_resp.body) | |
csrf_meta_param_tag = login_form_html.at_css('meta[name="csrf-param"]').freeze | |
csrf_meta_token_tag = login_form_html.at_css('meta[name="csrf-token"]').freeze | |
login_get_req_cookie = parse_set_cookies(login_get_resp.headers['Set-Cookie']) | |
login_post_resp = self.class.post('/login', { | |
follow_redirects: false, | |
headers: { | |
'User-Agent' => @user_agent, | |
'Cookie' => login_get_req_cookie.to_cookie_string | |
}, | |
body: { | |
'LoginForm' => { | |
'rememberMe' => '0', | |
'username' => @username, | |
'password' => @password, | |
}, | |
csrf_meta_param_tag['content'] => csrf_meta_token_tag['content'], | |
}, | |
}) | |
case login_post_resp.code | |
when 302 | |
@csrf_token = csrf_meta_token_tag['content'] | |
@identity_cookie = parse_set_cookies(login_post_resp.headers['Set-Cookie']) | |
return true | |
when 200 | |
raise 'Username or Password might not match' | |
else | |
raise 'Unknown login exception' | |
end | |
end | |
def registration | |
raise 'Not loggin yet' if @identity_cookie.nil? | |
reg_resp = self.class.get('/registration', { | |
follow_redirects: false, | |
headers: { | |
'User-Agent' => @user_agent, | |
'X-CSRF-Token' => @csrf_token, | |
'X-Requested-With' => 'XMLHttpRequest', | |
'Cookie' => @identity_cookie.to_cookie_string, | |
'Accept' => 'application/json, text/javascript, */*; q=0.01', | |
}, | |
}) | |
case reg_resp.code | |
when 200 | |
logger.info 'Registration succeed today' | |
when 500 | |
logger.info 'Registration failed, might already done' | |
end | |
end | |
private | |
def logger | |
@logger ||= ::Logger.new(STDOUT) | |
end | |
def parse_set_cookies(set_cookie) | |
cookie_hash = CookieHash.new | |
set_cookie.split(', ').each { |c| cookie_hash.add_cookies(c) } | |
cookie_hash | |
end | |
end | |
if __FILE__ == $0 | |
user_identity = {}.tap do |identity| | |
identity[:username] = ENV['USERNAME'].presence || ARGV[0] | |
identity[:password] = ENV['PASSWORD'].presence || ARGV[1] | |
end | |
site = YiiChina.new user_identity | |
site.registration if site.login | |
end |