ScrapingしてLDA写経

背景
---
自然言語処理をやりたくて、いろいろ調べていたところ、次のサイトを発見し、写経させていただきました。
ありがとうございました。
https://qiita.com/shizuma/items/44c016812552ba8a8b88

１年以上前の記事ということもあり、自分なりに少し修正は行いましたが、一番下に「今後の課題」として書きましたが、完ぺきとはいきませんでした。

上記参考サイトでは１０００ユーザまで実行可能なようですが、~~この記事のコードだと、**条件（２５ユーザまで）付きで実効可能**な感じです。~~

（20180127追記開始）
以前の投稿では、２５ユーザまでしか実行できないという条件付きだったのですが、エラー処理を加え、特に制約条件はなくなりました（と思います(^_^;)）。
とりあえず３ページ分スクレイピングし、６０ユーザまではOKであることは確認しました。
最初は５ページ１００ユーザで挑戦したのですが、Qiita APIの１時間あたりのアクセス上限？にかかってしまうようで、３ページ分６０ユーザで実行しました。
出力結果などは、修正後の結果に差し替えました。
（20180127追記終了）


~~条件付きではありますが、~~僕と同じように、とにかく自然言語処理してみたいという人、のお役に立てれば幸いです。

環境
---
Ubuntu 16.04
~~Windows10(Bash on Ubuntu on Windows)~~
Python 3.6.3 :: Anaconda, Inc.
anaconda Command line client (version 1.6.5)
jupyter notebook


1.ユーザ名の取得
---

まず、BeautifulSoupを使って、Qiitaのユーザランキングのページから、~~上位２０人（１ページ分）~~上位６０人（３ページ分）を取得。

- コード

```py

import requests
from bs4 import BeautifulSoup
import csv
import time

base_url = 'https://qiita-user-ranking.herokuapp.com/'
#max_page = 50
max_page = 3 # 1ページあたりユーザー20

qiita_users = []

for i in range(max_page):
    target_url = base_url + "?page=" + str(i + 1)
    target_html = requests.get(target_url).text
    soup = BeautifulSoup(target_html, 'html.parser')
    users = soup.select('main > p > a')

    for k, user in enumerate(users):
        qiita_users.append([(i*20 + k + 1), user.get_text()])

    time.sleep(1)
    print('scraping page: ' + str(i + 1))

f = open('qiita_users.csv', 'w') 
writer = csv.writer(f, lineterminator='\n')
writer.writerow(['user_id', 'name'])
for user in qiita_users:
    print(user)
    writer.writerow(user)
f.close()
```

- 出力結果


「qiita_users.csv」として、次のようなcsvファイルが作成されます。

```
scraping page: 1
[1, 'hirokidaichi']
[2, 'jnchito']
[3, 'suin']
・・・
（以下、割愛）
```

2. ユーザがフォローしているタグの取得
---

ランキング上位２０名のユーザがフォローしているタグ（pythonとか、Gitとか）を、QiitaAPIをつかったスクレイピングにより取得。

ここで問題発生。
参考にしたソースコードは１年以上前のもので、現在のQiitaAPIはV1から「V2」に変更されていた。
なんとか「V2」で情報を取得はできたが、取得できる情報の内容が変更されている感じ。

- コード

```py

import csv, requests, os.path, time

f = open('qiita_users.csv', 'r')
reader = csv.reader(f)
next(reader)

qiita_tags = []
qiita_user_tags = []

if os.path.isfile('qiita_user_tags.csv'):
    user_tag_num = sum(1 for line in open('qiita_user_tags.csv'))
else:
    user_tag_num = 0

if os.path.isfile('qiita_tags.csv'):
    f_tag = open('qiita_tags.csv', 'r')
    reader_tag = csv.reader(f_tag)
    qiita_tags = [tag[0] for tag in reader_tag]

f_tag = open('qiita_tags.csv', 'w')
writer_tag = csv.writer(f_tag, lineterminator='\n')
f_user_tag = open('qiita_user_tags.csv', 'a')
writer_user_tag = csv.writer(f_user_tag, lineterminator='\n')

for user in reader:
    if user_tag_num < int(user[0]):
#        target_url = 'https://qiita.com/api/v1/users/' + user[1] + '/following_tags'
        target_url = 'https://qiita.com/api/v2/users/' + user[1] + '/following_tags' #「v1」から「v2」へ変更
        print('scraping: ' + user[0])

        try:
            result = requests.get(target_url)
        except requests.exceptions.HTTPError as e:
            print(e)
            break
        target = result.json()

#        if 'error' in target:
#            print(target['error'])
#            if target['error'] == 'Rate limit exceeded.':
#                break
#            continue

#（20180127追記）エラー処理開始        
        if 'type' in target:
            print(target['type'])
            if target['type'] == 'not_found.':
                break
            continue
#（20180127追記）エラー処理終了  


        qiita_user_tag = [int(user[0])]
        for tag in target:
            #if tag['name'] in qiita_tags:
                #qiita_user_tag.append(qiita_tags.index(tag['name']) + 1)
            if tag['id'] in qiita_tags: #tag['name']から、tag['id']へ変更
                qiita_user_tag.append(qiita_tags.index(tag['id']) + 1) #tag['name']から、tag['id']へ変更
            else:
                #qiita_tags.append(tag['name'])
                qiita_tags.append(tag['id']) #tag['name']から、tag['id']へ変更
                tag_num = len(qiita_tags)
                qiita_user_tag.append(tag_num)
        qiita_user_tags.append(qiita_user_tag)
        time.sleep(1)

for tag in qiita_tags:
    writer_tag.writerow([tag])
writer_user_tag.writerows(qiita_user_tags)

f_tag.close()
f_user_tag.close()
f.close()
```

- 出力結果（qiita_tags.csv）

```
GoogleAppsScript
ActionScript
JavaScript
CSS
・・・
（以下割愛）
```


- 出力結果（qiita_user_tags.csv）

```
1,1,2,3,4
2,5,6,7,8,9,10,3,11,12,13,14,15,16,17,18,19,20
3,21,22,17,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39
4,40,41,42,43,44,45,46,47,48,49,50,3,51
5,52,53,54,55,56,57,58,59,60,61,62,63,64,65,43,66,67,68,69,70
6,71,35,72,73,74,62,66,75,18,76,77,78,41,79,80,15,42,81,82,47
（以下、割愛）
```

３．出力結果の成型
---

- コード

```py

import csv
import gensim
from pandas import DataFrame

tag_name_dict = {}
with open('qiita_tags.csv', 'r') as f_tags:
    tag_reader = csv.reader(f_tags)

    for i, row in enumerate(tag_reader):
        tag_name_dict[(i+1)] = row[0]


user_tags_dict = {}
with open('qiita_user_tags.csv', 'r') as f_user_tags:
    user_tags_reader = csv.reader(f_user_tags)

    for i, row in enumerate(user_tags_reader):
        user_tags_dict[int(row[0])] = row[1:-1]

tags_list = []
for k, v in user_tags_dict.items():
    tags_list.extend(v)

once_tags = [tag for tag in tags_list if tags_list.count(tag) == 1]

user_tags_dict_multi = { k: [tag for tag in user_tags if not tag in once_tags] for k, user_tags in user_tags_dict.items()}

user_tags_dict_multi = {k: v for k, v in user_tags_dict_multi.items() if not len(v) == 0}

corpus = [[(int(tag), 1) for tag in user_tags]for k, user_tags in user_tags_dict_multi.items()]

lda = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=15)

topic_top10_tags = []
for topic in lda.show_topics(-1, formatted=False):
    topic_top10_tags.append([tag_name_dict[int(tag[0])] for tag in topic[1]])

topic_data = DataFrame(topic_top10_tags)
print(topic_data)
print("------------------")

c = [(1, 1), (2, 1)] 
for (tpc, prob) in lda.get_document_topics(c):
    print(str(tpc) + ': '+str(prob))
```

- 実行結果

```
              0             1           2           3                    4  \
0         Swift           iOS      docker         Git          Objective-C   
1          GLSL          機械学習     Node.js  JavaScript          ShellScript   
2         Qiita         Swift        chef      iPhone           JavaScript   
3        docker        Elixir       Hubot     vagrant               itamae   
4           gcp        lambda         es6       MySQL              GraphQL   
5       Node.js  CoffeeScript         iOS        機械学習                 HTML   
6         RSpec           Zsh       Qiita       Redis                MySQL   
7          機械学習  DeepLearning       Keras       Emacs                    R   
8         Swift    TypeScript     angular    Angular2                 gulp   
9        Elixir    Blockchain  TensorFlow       Swift             solidity   
10       docker       Polymer     Phoenix      Erlang                 lisp   
11       Heroku        Kotlin      vue.js    dotfiles               Arukas   
12  RaspberryPi          CSS3      docker           R                Emacs   
13   JavaScript       Android  TypeScript     Haskell              Node.js   
14       Python            Go       Linux     Node.js  googlecomputeengine   


             5             6             7             8                9  
0       MacOSX        iPhone          Ruby         Rails           GitHub  
1        Swift      HoloLens       Android  DeepLearning  MachineLearning  
2        Rails       MongoDB           api  CoffeeScript           Python  
3       GitLab        Ruboty          TOML       crystal       JavaScript  
4   JavaScript         Emacs         Swift       Android          Haskell  
5   TensorFlow      Ethereum           CSS       Chainer   Cryptocurrency  
6        Rails          Ruby  CoffeeScript           Git               Go  
7       Python  CoffeeScript         Qiita        docker       TensorFlow  
8          Vim            Go       Android          機械学習            Xcode  
9     Ethereum    atom-shell          chef     Terraform           GitLab  
10      Elixir         nginx         Swift          GLSL       TypeScript  
11      pandas         React         mecab    JavaScript            Emacs  
12        Java        Chrome       jasmine    TypeScript             HTML  
13        HTML        golang            Go           SQL             Ruby  
14          C#         MySQL          Ruby    JavaScript      ShellScript  

------------------
0: 0.022222246643926906
1: 0.022222263995008054
2: 0.022222255047640332
3: 0.02222229444346636
4: 0.6888882649724504
5: 0.022222267884482987
6: 0.02222226608552513
7: 0.02222225896685582
8: 0.022222259566950935
9: 0.02222228246944507
10: 0.02222226546848409
11: 0.02222229498350666
12: 0.02222226471356833
13: 0.022222261560756094
14: 0.022222253197932956
```
この投稿が、何かのお役にたてればうれしいです。