lib/instagrammer/user.rb
# frozen_string_literal: true
class Instagrammer::User
include Capybara::DSL
include Instagrammer::Utils
attr_reader :posts
def initialize(username)
@username = username.delete_prefix("@")
@data = nil
@posts = []
end
def public?
get_data unless @data
@status == :public
end
def meta
get_data unless @data
if @status == :not_found
raise Instagrammer::UserNotFound.new("Private account: #{@username}")
else
@meta
end
end
def follower_count
meta[:followers]
end
def following_count
meta[:following]
end
def post_count
meta[:posts]
end
def data
get_data unless @data
case @status
when :private then raise Instagrammer::PrivateAccount.new("Private account: #{@username}")
when :not_found then raise Instagrammer::UserNotFound.new("User not found: #{@username}")
when :invalid then raise Instagrammer::UserInvalid.new("User invalid: #{@username}")
else @data
end
end
def name
data["name"]
end
def username
data["alternateName"].delete_prefix("@")
end
def avatar
data["image"]
end
def bio
data["description"]
end
def url
data["mainEntityofPage"]["@id"]
end
SHORTCODE_RE = /\/p\/(\S+)\/$/
def get_posts(limit)
shortcodes = []
i = 0
visit "https://www.instagram.com/#{@username}/"
while i < limit
post_links = page.all(:post_link)
if limit > post_links.size
page.execute_script "window.scrollTo(0,document.body.scrollHeight);"
post_links = page.all(:post_link)
end
shortcode = post_links[i]["href"].match(SHORTCODE_RE)[1]
shortcodes << shortcode
i += 1
end
@posts = shortcodes.collect { |code| Instagrammer::Post.new(code) }
end
private
def get_data
visit "https://www.instagram.com/#{@username}/"
@status = get_page_status
@meta = get_metadata unless @status == :not_found
if @status == :public
node = page.first(:json_ld, visible: false)
@data = JSON.parse(node.text(:all))
end
end
META_RE = /(?<followers>\S+) Followers, (?<following>\S+) Following, (?<posts>\S+) Posts/
def get_metadata
@meta = page.first(:meta_description, visible: false)["content"].match META_RE
end
end