LoginSignup
1
2

More than 5 years have passed since last update.

ScrapingしてLDA写経

Last updated at Posted at 2017-12-10

背景

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

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

上記参考サイトでは1000ユーザまで実行可能なようですが、この記事のコードだと、条件(25ユーザまで)付きで実効可能な感じです。

(20180127追記開始)
以前の投稿では、25ユーザまでしか実行できないという条件付きだったのですが、エラー処理を加え、特に制約条件はなくなりました(と思います(^_^;))。
とりあえず3ページ分スクレイピングし、60ユーザまではOKであることは確認しました。
最初は5ページ100ユーザで挑戦したのですが、Qiita APIの1時間あたりのアクセス上限?にかかってしまうようで、3ページ分60ユーザで実行しました。
出力結果などは、修正後の結果に差し替えました。
(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のユーザランキングのページから、上位20人(1ページ分)上位60人(3ページ分)を取得。

  • コード

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. ユーザがフォローしているタグの取得

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

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

  • コード

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
(以下、割愛)

3.出力結果の成型

  • コード

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

この投稿が、何かのお役にたてればうれしいです。

1
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2