(まだ途中だけどもとりあえず投稿)
#流れ
1.ブラウザを起動
2.インスタグラムにログイン
3.対象のアカウントのHTMLを取得
4.info辞書作成
5.投稿のURLを開く
6.HTML取得
7.#のリスト獲得
インスタグラムは直接スクレイピングを行うことが出来ない。
だから、ブラウザを介する必要がある。
#インストールするもの
・selenium
>クリックとかキーボード入力などの操作をプログラムで命令できる
・bs4(BeautifulSoup)
>取得したHTMLを解析する
・chromedriver-binary(バージョンはchromeより前のもの)
>ブラウザをプログラムで操作する
>chrome用のwebdriver
*webdriver:ブラウザを操作するライブラリ
#ソースコード
#個人の過去の投稿を取得
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import urllib.parse
import re
import bs4
import json
import time
import chromedriver_binary
LOGIN_ID = "**********"
PASSWORD = "********"
INSTAGRAM_DOMAIN = "https://www.instagram.com/"
MIN_COUNT = 10
ACCOUNT_ID = "#を取得したいアカウントのID"
#検索結果のurlを取得する
def get_url():
element = driver.find_element_by_id('react-root')
aTag = element.find_element_by_tag_name("a")
url = aTag.get_attribute("href")
return url
# driver取得
def get_driver():
# ヘッドレスモードでブラウザを起動
options = Options()
options.add_argument('--headless')
# ブラウザーを起動
driver = webdriver.Chrome(options=options)
return driver
# 対象ページ取得
def get_text_from_target_page(driver, first_flg, url):
# ターゲット
driver.get(url)
if first_flg:
# articleタグが読み込まれるまで待機(最大10秒)
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'article')))
else:
driver.implicitly_wait(10) # 見つからないときは、10秒まで待つ
#今表示しているページのコードを取得
text = driver.page_source
return text
# 正規表現で値を抽出
def get_search_value(ptn, str):
result = re.search(ptn, str)
if result:
return result.group(1)
else:
return None
#tag_info取得.
def get_info_tag(text):
soup = bs4.BeautifulSoup(text,features='lxml')
tags = []
try:
#(xil3iに#がある)
elems = soup.find_all(class_ = 'xil3i')
#print("elems",elems)
for elem in elems:
tag = elem.get_text()
tags.append(tag)
#print('繰り返しelem:',tag)
return tags
except:
return None
# info取得
def get_info_from_text(text):
soup = bs4.BeautifulSoup(text, features='lxml')
try:
info = {}
id_ = []
# 投稿(v1Nh3 kIKUG _bz0w)
elems = soup.find_all(class_="v1Nh3")
#print("info_elems:",elems)
for elem in elems:
a_elem = elem.find("a")
href = a_elem["href"]
url = INSTAGRAM_DOMAIN + href
post_id = get_search_value("\/p\/(.*)\/", href)
#辞書からurlを引き出すためのid
id_.append(post_id)
# img情報
img_elem = elem.find("img")
alt = img_elem["alt"]
src = img_elem["src"]
post_dic = {}
post_dic["url"] = url
post_dic["alt"] = alt
post_dic["src"] = src
info[post_id] = post_dic
return info,id_
except:
return None
# 最後の要素までスクロール
def scroll_to_elem(driver, footer_move_flg):
try:
if footer_move_flg:
last_elem = driver.find_element_by_id("fb-root")
actions = ActionChains(driver);
actions.move_to_element(last_elem);
actions.perform();
else:
# 最後の要素の一つ前までスクロール
elems = driver.find_elements_by_class_name("weEfm")
last_elem = elems[-1]
actions = ActionChains(driver);
actions.move_to_element(last_elem);
actions.perform();
return True
except:
return False
# 投稿件数取得
def get_post_count(text):
try:
json_str = get_search_value("window._sharedData = (.*);<\/script>", text)
dict = json.loads(json_str)
post_count = dict["entry_data"]["TagPage"][0]["graphql"]["hashtag"]["edge_hashtag_to_media"]["count"]
return post_count
except:
return MIN_COUNT
#インスタグラムログイン
def do_login(driver):
# ログインURL
login_url = INSTAGRAM_DOMAIN + "accounts/login/"
driver.get(login_url)
# 電話、メールまたはユーザー名のinput要素が読み込まれるまで待機(最大10秒)
elem_id = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.NAME, "username"))
)
try:
# パスワードのinput要素
elem_password = driver.find_element_by_name("password")
if elem_id and elem_password:
# ログインID入力
elem_id.send_keys(LOGIN_ID)
# パスワード入力
elem_password.send_keys(PASSWORD)
# ログインボタンクリック
elem_btn = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.XPATH, '//*[@id="loginForm"]/div/div[3]/button'))
)
actions = ActionChains(driver)
actions.move_to_element(elem_btn)
actions.click(elem_btn)
actions.perform()
# 適当(3秒間待つように対応しています)
time.sleep(3)
# 遷移
# 遷移後のURLでログイン可否をチェック
perform_url = driver.current_url
if perform_url.find(login_url) == -1:
# ログイン成功
return True
else:
# ログイン失敗
return False
else:
return False
except:
return False
if __name__ == '__main__':
# url
url = "https://www.instagram.com/" + ACCOUNT_ID + "/"
# ブラウザーを起動
driver = get_driver()
login_flg = do_login(driver)
print(login_flg)
# 対象ページのhtmlソース取得
text_0 = get_text_from_target_page(driver, True, url)
#element = driver.find_element_by_link_text('helf')
post_count = get_post_count(text_0)
print("合計:" + str(post_count))
info_all = {}
count_info = 0
buf_count_info = 0
tag_list = []
while count_info < MIN_COUNT:
# スクロール後対象ページのhtmlソース取得
text_1 = driver.page_source
info,id_ = get_info_from_text(text_1)
for i in id_:
url = info[i]["url"]
#個人の投稿ページのURLを開きHTMLを取得
html_account = get_text_from_target_page(driver,True,url)
#次に#の情報を取得する(xil3i)
tags = get_info_tag(html_account)
tag_list += tags
if not None:
info_all.update(info)
count_info = len(info_all)
time.sleep(1)
print(count_info)
if buf_count_info==count_info:
time.sleep(3)
result_flg = scroll_to_elem(driver, False)
#buf_count_info = count_info
if post_count <= count_info:
break
#作成した#のリストの
result_tag = set(tag_list)
result_tag = list(result_tag)
print(result_tag)
driver.quit()
#ブラウザを起動
options.add_argument('--headless')を書くと裏でブラウザが起動され表示されない。
多分--headlessを他の物に変更すると別の機能があるんだろうと思う。
# driver取得
def get_driver():
# ヘッドレスモードでブラウザを起動
options = Options()
options.add_argument('--headless')
# ブラウザーを起動
driver = webdriver.Chrome(options=options)
return driver
#インスタグラムにログイン
##driver.get()
urlを開いている。引数は開きたいurl。
login_url = INSTAGRAM_DOMAIN + "accounts/login/"
:インスタグラムのログイン画面のurlを指定。
##elem_id=WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.NAME,"username")))
elem_idに電話番号やユーザーネームを入れる場所の情報(input要素)が入る。
下記参考サイト
##try:
実行したい処理
##except:
tryが出来なかったときに実行する処理
##send.key()
input要素に値を入力する
引数を変更することでEnterkeyを押すこともできる
参考
##xpathとは
htmlを指定するpath
こんなやつ↓↓
/bookstore/book/author
#インスタグラムログイン
def do_login(driver):
# ログインURL
login_url = INSTAGRAM_DOMAIN + "accounts/login/"
driver.get(login_url)
# 電話、メールまたはユーザー名のinput要素が読み込まれるまで待機(最大10秒)
elem_id = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.NAME, "username"))
)
try:
# パスワードのinput要素
elem_password = driver.find_element_by_name("password")
if elem_id and elem_password:
# ログインID入力
elem_id.send_keys(LOGIN_ID)
# パスワード入力
elem_password.send_keys(PASSWORD)
# ログインボタン
elem_btn = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.XPATH, '//*[@id="loginForm"]/div/div[3]/button'))
)
actions = ActionChains(driver)
actions.move_to_element(elem_btn) #ログインボタンまで移動
actions.click(elem_btn) #クリックの命令
actions.perform() #実行
# 適当(3秒間待つように対応しています)
time.sleep(3)
# 遷移
# 遷移後のURLでログイン可否をチェック
perform_url = driver.current_url
if perform_url.find(login_url) == -1:
# ログイン成功
return True
else:
# ログイン失敗
return False
else:
return False
except:
return False