instagramの投稿から#を取得する

（まだ途中だけどもとりあえず投稿）

#流れ
1.ブラウザを起動
2.インスタグラムにログイン
3.対象のアカウントのHTMLを取得
4.info辞書作成
5.投稿のURLを開く
6.HTML取得
7.＃のリスト獲得

インスタグラムは直接スクレイピングを行うことが出来ない。
だから、ブラウザを介する必要がある。

#インストールするもの
・selenium
＞クリックとかキーボード入力などの操作をプログラムで命令できる

・bs4(BeautifulSoup)
＞取得したHTMLを解析する

・chromedriver-binary(バージョンはchromeより前のもの）
＞ブラウザをプログラムで操作する
＞chrome用のwebdriver

＊webdriver：ブラウザを操作するライブラリ

#ソースコード
```python:main.py
#個人の過去の投稿を取得
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を他の物に変更すると別の機能があるんだろうと思う。

```python:
# 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要素)が入る。

下記参考サイト

https://qiita.com/uguisuheiankyo/items/cec03891a86dfda12c9a

##try:
実行したい処理
##except:
tryが出来なかったときに実行する処理

##send.key()
input要素に値を入力する
引数を変更することでEnterkeyを押すこともできる

参考

https://www.seleniumqref.com/api/python/element_set/Python_special_send_keys.html

##xpathとは
htmlを指定するpath
こんなやつ↓↓
/bookstore/book/author 

https://www.octoparse.jp/blog/xpath-introduction/

[![Image from Gyazo](https://i.gyazo.com/a527e97c0f71583d42cf1fbf6839866a.png)](https://gyazo.com/a527e97c0f71583d42cf1fbf6839866a)

```python:
#インスタグラムログイン
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 
```