☆☆ 新着記事 ☆☆

2019年4月28日日曜日

PythonのPandasで、取得したtweepyのデータをmatplotlibでグラフにする。


PythonのPandasで、取得したtweepyのデータをmatplotlibでグラフにする。
公式:
https://matplotlib.org/gallery/index.html
>pip install matplotlib
で、インストールしておいて。



Matplotlibを使う時の2つのアプローチがある。本投稿では、記述が簡単な、2つ目のpyplotによる記述が中心。

オブジェクト指向インターフェース




Pyplotインターフェース
plt.なんとかで全部済ませる流儀。

(基本構文)
import matplotlib.pyplot as plt

price = [100, 250, 380, 500, 700]
number = [1, 2, 3, 4, 5]

# グラフを書く
plt.plot(price, number)

# グラフのタイトル
plt.title("price / number")

# x軸のラベル
plt.xlabel("price")

# y軸のラベル
plt.ylabel("number")

# 表示する
plt.show()

https://qiita.com/skotaro/items/08dc0b8c5704c94eafb9




import tweepy as tw       
import pandas as pd   
import numpy as np     
import matplotlib.pyplot as plt
import matplotlib as style
from credentials import *

def twitter_setup():
    auth = tw.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    api = tw.API(auth,wait_on_rate_limit=True)
    return api
extractor = twitter_setup()

tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=100)
print("Number of tweets extracted: {}.\n".format(len(tweets)))

for tweet in tweets:
    print(tweet.text, '+Like', tweet.favorite_count, '+Retweet', tweet.retweet_count)

tweet_df = pd.DataFrame(data=[[tweet.created_at,tweet.text, tweet.favorite_count,tweet.retweet_count] for tweet in tweets],
                            columns=['Date','Tweet','Like','RT'])

♯ df の 条件に合ったrowを削除
tweet_df2 = tweet_df[tweet_df.Like !=0]
print(tweet_df2)

♯ df の ソート
tweet_df3 = tweet_df.sort_values('Like', ascending=False)
print(tweet_df3.head(5))
tweet_df4 = tweet_df.sort_values('RT', ascending=False)
print(tweet_df4.head(5))

♯Graph表示
plt.style.use('seaborn-darkgrid')

//x軸、y軸の値の順番で指定(pdにしなくて、普通のリストでも良い)
plt.plot(tweet_df2. Date, tweet_df2.Like, color="green",marker="D",markersize=2,
         markeredgewidth=3, markeredgecolor="blue", markerfacecolor="lightblue")

plt.legend()

plt.title("# of Liked in the past 200 Tweets")
plt.xlabel("date")
plt.ylabel("Likes")
plt.tick_params(axis='x', which='major', labelsize=6)  # tick(目盛表示の指定)

plt.savefig('C:/Users/ path to /graph.png')
plt.show()

# tick(目盛表示の大きさの指定)
X軸の目盛単位の表示の大きさを指定しています。 Y軸も同様に指定が可能。
両方の大きさを変えたい場合、軸を指定しなければ、両方に適用されます。
plt.tick_params(labelsize=6)


こんなグラフができます。


*注)
X軸のラベルが多すぎて、重なってしまう場合、X軸の値を日付型にすれば、表示を自動調整してくれます。 文字(Str)型から日付(date)型への変換の仕方は、
【 PythonのDateTime.Object(UTC) のタイムゾーン変更 - 実践編


◇ Bar Chart
plt.bar(tweet_df2. Datetweet_df2.Like,)

fig = plt.figure(figsize=(7, 4))
ax = fig.add_subplot(1, 1, 1, fc='#191970')

plt.bar(x_axis, y_axis, color='#98fb98')
plt.tick_params( labelsize=7)
plt.title('Population at 3pm in the vicinity of Tokyo Station')
plt.xlabel('Date')
plt.ylabel('% (Percent)')
plt.grid(True)

で、こんな感じ。




◇ Pie Chart

colors = ['green', 'blue', 'red']
data = [35%, 45%, 20%]
labels =[ 'Positive''Neutral','Negative']

## use matplotlib to plot the chart
plt.pie(
   x=data,
   shadow=True,
   colors=colors,
   labels=labels,
)
plt.savefig('C:/Users/ path to /graph.png')
plt.show()

こんな感じのグラフができます。


X軸を日付にした場合の表示間隔の調整
*やり方1: X軸の値を日付にする
#https://bunseki-train.com/setting_ticks_by_matplotlib_dates/

fig = plt.figure(figsize=(7, 4))
ax = fig.add_subplot(1, 1, 1, fc='#191970')

plt.style.use=('seaborn-dark')
plt.plot(x_axis, y_axis, color='#98fb98')

ax.xaxis.set_major_locator(mdates.HourLocator(byhour=range(0, 24, 3), tz=None))
ax.xaxis.set_minor_locator(mdates.HourLocator(byhour=range(0, 24, 1), tz=None))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d\n%H:%M:%S"))

# 次の2行は軸ラベルを回転させるために使用
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, fontsize=5)

plt.show()

とやると以下のようになる。 値がない日付も間隔をとってしまう。




 複数のグラフを並べて表示する

figure命令を使用し、add_subplot命令でそれぞれの領域に描画


*書き方:add_subplot(行数, 列数, 番号)


import matplotlib.pyplot as plt
fig = plt.figure()

# 1行2列の左
labels = ["A", "B", "C", "D", "E", "F"]
x = range(0, 6)
y = [10, 20, 30, 40, 50, 60]
ax1 = fig.add_subplot(1, 2, 1)
ax1.bar(x, y, tick_label = labels)
ax1.set_title("graph1")

# 1行2列の右
labels = ["E", "D", "C", "B", "A"]
y = [10, 20, 30, 40, 50]
ex = [0, 0, 0, 0, 0.1]
ax2 = fig.add_subplot(1, 2, 2)
ax2.pie(y, explode = ex, labels = labels, autopct = '%1.1f%%', startangle = 90)
ax2.set_title("graph2")

# グラフを表示する
plt.show()






2019年4月27日土曜日

object of type 'ItemIterator' has no len()

Tweepyの Cursor(api.search, q=' ')で取得したデータが、上記のエラーになる件。

1. 問題の事象 

以下がコードの該当箇所。

app.py

extractor = twitter_setup()
search_words = "Trump" + " -filter:retweets"
since=date_since = "2019-04-25"

tweets = tw.Cursor(extractor.search, q=search_words, lang="en", since=date_since).items(5)

print("Number of tweets extracted: {}.\n".format(len(tweets)))

for tweet in tweets:
    print(tweet.text)

tweet_text = pd.DataFrame(data=[tweet.text for tweet in tweets],columns=['Twwet'])
print(tweet_text)

Output:

Traceback (most recent call last):
  File "C:\app.py", line 28, in <module>
    print("Number of tweets extracted: {}.\n".format(len(tweets)))
TypeError: object of type 'ItemIterator' has no len()


この、
print("Number of tweets extracted: {}.\n".format(len(tweets))) がない場合

for tweet in tweets:
    print(tweet.text)


以降が実行されて、以下がOutputされる。


Output:
Peter Funt, who also wrote that "Trump should get credit for his awesomeness," in a different o
pinion piece, wrote… https://t.co/TlQEfzDUPp
@nadeema @Emeraldleah @JoeBiden What planet are you living on?
He is still extremely popular and would easily dust Trump
Excited for the first animated film to make a Trump joke
@RonMatthews82 @Steigerworld Saudi Arabia is home to some of the most radical Islamist extremist, dude. Trump is da… https://t.co/8V7L4i4gxM
i wanna vent somewhere but i think theres a trump supporter or two in every server or twitter i
 have and i dont wan… https://t.co/beijxcUkyz

Empty DataFrame
Columns: [Twwet]
Index: []

となり、tweetに格納された.text属性データはプリント・アウトできるが、PandasのDataFrameにすることはできない。

2. 調査

調べると、このobject of type 'ItemIterator' は、tweepyパッケージのCursor.pyでdefineされたClass Objectらしい。

cursor.py

class ItemIterator(BaseIterator):
    def __init__(self, page_iterator):
        self.page_iterator = page_iterator
        self.limit = 0
        self.current_page = None
        self.page_index = -1
        self.num_tweets = 0
    def next(self):
        if self.limit > 0:
            if self.num_tweets == self.limit:
                raise StopIteration
        if self.current_page is None or self.page_index == len(self.current_page) - 1:
            # Reached end of current page, get the next page...
            self.current_page = self.page_iterator.next()
            self.page_index = -1
        self.page_index += 1
        self.num_tweets += 1
        return self.current_page[self.page_index]
    def prev(self):
        if self.current_page is None:
            raise TweepError('Can not go back more, at first page')
        if self.page_index == 0:
            # At the beginning of the current page, move to next...
            self.current_page = self.page_iterator.prev()
            self.page_index = len(self.current_page)
            if self.page_index == 0:
                raise TweepError('No more items')
        self.page_index -= 1
        self.num_tweets -= 1
        return self.current_page[self.page_index]

というClassとして定義されている。

>>> type(tweets)
<class 'tweepy.cursor.ItemIterator'>

>>> print(tweets[0])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'ItemIterator' object does not support indexing <== これ良く出てくる。

>>> tweets.__dict__.keys()
dict_keys(['page_iterator', 'limit', 'current_page', 'page_index', 'num_tweets'])

>>> print(dir(tweets))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'current_page', 'limit', 'next', 'num_tweets', 'page_index', 'page_iterator', 'prev']





以前の「PythonのPandasで、取得したtweepyのデータを整理する」で実施した
<class 'tweepy.models.ResultSet'>との比較は、こちらでどうぞ。
https://mycodingjp.blogspot.com/2019/04/pythonpandastweepy.html




search_words = "Trump"
since=date_since = "2019-04-25"

tweets = tw.Cursor(extractor.search, q=search_words, lang="en", since=date_since).items(5)
print([tweet.text for tweet in tweets])


tweets = tw.Cursor(extractor.search, q=search_words, lang="en", since=date_since).items(5)
users_locs = [[tweet.user.screen_name, tweet.user.location] for tweet in tweets]
for users_loc in users_locs:
    print(users_loc)

tweetsをprintする毎に定義しないといけない。変数 users_locの前に、再定義しないとPrintできない。

["RT @johnlundin: CNN's Jim Acosta rips Trump after he refuses to defend his repeated 'coup' cl
aims: 'I don't think he understands what he's…", 'RT @gatewaypundit: Trump Announces Withdrawa
l From U.N. Small Arms Treaty -- Signs Doc in Front of NRA, Tosses Pen Into Crowd (VIDEO) https
…', "RT @ddale8: As reported, Trump announces he will revoke the US signature from the global
arms-trade treaty. People cheer. He says he's impr…", 'RT @RudyGiuliani: The article below is
one of a number showing a possible conspiracy(collusion)between DNC and Clinton operatives and
Ukrai…', 'RT @robreiner: Every day Trump prevents anyone from his administration from testifyi
ng to Congress is another day he commits obstruction of…']

['JoeEbert11', 'New Hampshire, USA']
['GmMaklinesr', 'Virginia']
['gfeinholtz', 'Tucson']
['joseph_feeny', 'Ohio, USA']
['moreresistance2', 'California, USA']



3. 対策

インストールされているtweepyのばージョンとPython3のVersionを確認する。

>pip freeze
tweepy  3.7.0

tweepyのバージョンとサポート状況
https://github.com/tweepy/tweepy

Python 2.7, 3.4, 3.5, 3.6, & 3.7 are supported.

半年前にアップされたチュートリアルでは、tweepy3.6が最新で、Python3.7はサポートされていなかったらしいが、自分がインストールしたバージョン(3.7.0)、既にPython3.7をサポートしているようだ。


search_words = "Trump"
since=date_since = "2019-04-25"

tweets = tw.Cursor(extractor.search, q=search_words, lang="en", since=date_since).items(5)
users_locs = [[tweet.user.screen_name, tweet.user.location] for tweet in tweets]
for users_loc in users_locs:
    print(users_loc)

tweet_text = pd.DataFrame(data=users_locs,columns=['User','Location'])
print(tweet_text)


['60andmoonwalkin', 'United States']
['CritterFL', 'Pittsburgh, PA']
['usmaan_aisha', '']
['alahley', 'Bend, Oregon']
['debos111', '']
              User        Location
0  60andmoonwalkin   United States
1        CritterFL  Pittsburgh, PA
2     usmaan_aisha
3          alahley    Bend, Oregon
4         debos111

Tweepy Methodで取得できるデータとpandas メモ

Pandasのデータフレームにするのは、直観的に分かります。

extractor = twitter_setup()
tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=5)

print("Number of tweets extracted: {}.\n".format(len(tweets)))

for tweet in tweets:
    print(tweet.text,tweet.favorite)

tweet_text = pd.DataFrame(data=[(tweet.text,tweet.favorite) for tweet in tweets],columns=['Twwet','Likes'])
print(tweet_text)

(output)

Number of tweets extracted: 5.

THANK YOU @NRA! #NRAAM https://t.co/SWkpe1eFhT 27513
“U.S. Economy Grows 3.2% in Q1, Smashing Expectations” https://t.co/HltPdlkOD0 39206
RT @WhiteHouse: "With God as our witness, we swear today that we will defend our rights, we wil
l safeguard our freedoms, we will uphold our… 0
RT @WhiteHouse: “Under my Administration, we will never surrender American sovereignty to anyo
ne. We will never allow foreign bureaucrats t… 0
Spoke to Saudi Arabia and others about increasing oil flow. All are in agreement. The Californi
a tax on gasoline is… https://t.co/znQjuoNReT 46372

                                               Twwet  Likes
0     THANK YOU @NRA! #NRAAM https://t.co/SWkpe1eFhT  27513
1  “U.S. Economy Grows 3.2% in Q1, Smashing Expec...  39206
2  RT @WhiteHouse: "With God as our witness, we s...      0
3  RT @WhiteHouse: “Under my Administration, we w...      0
4  Spoke to Saudi Arabia and others about increas...  46372


(参考)
JSON形式に
#for tweet in tw.Cursor(extractor.search, q='Trump').items(5):
#    tweets.append(tweet._json)

2019年4月26日金曜日

Tweepyで取得したツイートをFlaskでWebに表示する

前回に取得したTwitterのコンテンツを、FlaskでWebに表示します。

tweetオブジェクトに格納された .text / .favourite_count/ retweet_count / .created_at を属性指定して表示させます。

app.py

import tweepy           # To consume Twitter's API
import pandas as pd     # To handle data
import numpy as np      # For number computing
from flask import Flask, render_template, request


app = Flask(__name__)
# We import our access keys:
from credentials import *    # This will allow us to use the keys as variables
# API's setup:
def twitter_setup():
    """
    Utility function to setup the Twitter's API
    with our access keys provided.
    """
    # Authentication and access using keys:
    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    # Return API with authentication:
    api = tweepy.API(auth)
    return api

# We create an extractor object:
extractor = twitter_setup()
# We create a tweet list as follows:
tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=30)

@app.route('/')
def index():
    return render_template("index.html", tweets=tweets)

if __name__ == '__main__':
     app.run(debug=True)



templates/index.html

<!DOCTYPE html><html lang="ja">
<head>
<meta charset="utf-8">
</head>
<body>
 {% for tweet in tweets %}
 <hr>
 <p>{{tweet.text}} </p>
 <p>Like Count is : {{tweet.favorite_count}}  & RT Count is : {{tweet.retweet_count}}</p>
 <p>Created at : {{tweet.created_at}} </p>
 {% endfor %}
</body>
</html>


(Output)




Tweetの内容と、Like, Retweet, 時間が表示されました。


2. Pandas DataFrameをFlask HTMLに渡す。

app.py

tweet_df2 = tweet_df[tweet_df.Like !=0]

@app.route('/')
def index():
   
    return render_template("index.html", tables=[tweet_df2.head(5).to_html(classes='data')], titles=Like_df.columns.values)

inex.html

{% for table in tables %}
            {{titles[loop.index]}}
            {{ table|safe }} // htmlタグを解釈するため。
{% endfor %}


imgファイル、を含めて表示してみる。



app.py

import tweepy as tw         
import pandas as pd   
import numpy as np     
import matplotlib.pyplot as plt
import matplotlib as style
from credentials import *
from flask import Flask, render_template, request

app = Flask(__name__)

def twitter_setup():
    auth = tw.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    api = tw.API(auth,wait_on_rate_limit=True)
    return api

extractor = twitter_setup()

tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=200)

tweet_df = pd.DataFrame(data=[[tweet.created_at,tweet.text, tweet.favorite_count,tweet.retweet_count] for tweet in tweets],
                            columns=['Date','Tweet','Like','RT'])

tweet_df2 = tweet_df[tweet_df.Like !=0]
Like_df = tweet_df.sort_values('Like', ascending=False)
Like_df_top5 = Like_df.head(5)

plt.style.use('seaborn-darkgrid')
plt.plot(tweet_df2. Date, tweet_df2.Like, color="green",marker="D",markersize=2,
         markeredgewidth=3, markeredgecolor="blue", markerfacecolor="lightblue")

plt.savefig('C:/Full Path to /static/graph.png')

@app.route('/')
def index():
   
    return render_template("index.html", tables=[Like_df_top5.to_html(classes='data')], titles=Like_df_top5.columns.values)

if __name__ == '__main__':
    app.run(debug=True)




templates/index.html

<!DOCTYPE html><html lang="ja">
<head>
<meta charset="utf-8">
</head>
<body>

<img src="/static/graph.png" alt="" width="" height="" border="0" />
<hr>
{% for table in tables %}
    {{titles[loop.index]}}
    {{ table|safe }}
{% endfor %}

</body>
</html>







因みに、
{% for table in tables %}
    {{ table }}

だと、以下のように<html>タグが含まれたデータが格納されている、

<table border="1" class="dataframe data"> <thead> <tr style="text-align: right;"> <th></th> <th>Date</th> <th>Tweet</th> <th>Like</th> <th>RT</th> </tr> </thead> <tbody> <tr> <th>175</th> <td>2019-04-18 13:57:33</td> <td>https://t.co/222atp7wuB</td> <td>400026</td> <td>116858</td> </tr> <tr> <th>126</th> <td>2019-04-21 22:35:16</td> <td>How do you impeach a Republican President for ...</td> <td>270502</td> <td>63660</td> </tr> <tr> <th>133</th> <td>2019-04-21 11:04:01</td> <td>Happy Easter! I have never been happier or mor...</td> <td>229848</td> <td>38652</td> </tr> <tr> <th>127</th> <td>2019-04-21 14:23:37</td> <td>Can you believe that I had to go through the w...</td> <td>188850</td> <td>41816</td> </tr> <tr> <th>164</th> <td>2019-04-19 20:47:34</td> <td>....big, fat, waste of time, energy and money ...</td> <td>180403</td> <td>41720</td> </tr> </tbody>< /table>

この値をひとつずつ表示させるのは

{% for index, row in dfs.iterrows() %}
<div>{{row["Date"]}}</div>
<div>{{row["Tweet"]}}</div>
<div>{{row["Like"]}}</div>
<div>{{row["RT"]}}</div>
{% endfor %}





Simpleですが、今回はこれで終わりです。

2019年4月25日木曜日

PythonのPandasで、取得したtweepyのデータを整理する

tweepyでデータをとると言えば、アメリカのトランプ大統領ですね。 このポストでは、TwitterのAPIであるtweepyを使って、ツイートのデータを取得して、Pandas/NumPyで取得したデータを加工しやすいように整理します。



使用するPythonのライブラリは、

Pandas : 最早Pythonの定番のデータ構造化用ライブラリです。
NumPy: データの構造を更に加工しやすい用に整理してくれます。
(pandasをインストールするとついてきます。)

tweepy: twitterのデータを簡単に取得できるようにするAPIです。

どれも、pipでインストールできますので、インストールしてください。 又、tweepyを利用する為には、最初にtwitterのdeveloperアカウントを登録して、認証用のコードを取得しておく必要があります。 やり方はネットに沢山書かれてますので。(ちなみに、アカウント承認に数日かかった、という投稿も目にしますが、自分の場合は即時にアカウント承認されました。 色々ですね。)



1. tweepyでTwitterのデータにアクセスする為の基本

次の2つのpyファイルを作って、同じフォルダに入れる。

credential.py

CONSUMER_KEY    = ' 自分のコードを書いてください '
CONSUMER_SECRET =  ' 自分のコードを書いてください '
# Access:
ACCESS_TOKEN  = ' 自分のコードを書いてください '
ACCESS_SECRET = ' 自分のコードを書いてください '

app.py

import tweepy
import pandas as pd     
import numpy as np     

from credentials import *    # This will allow us to use the keys as variables

# API's setup:
def twitter_setup():
    """
   Twitter's API set up with our access keys provided.
    """
    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    api = tweepy.API(auth)
    return api

extractor = twitter_setup()
tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=30)

取得したデータの処理
♯ ① 取得したtweetの個数表示
print("Number of tweets extracted: {}.\n".format(len(tweets)))

♯ ② 取得したtweetのtext表示
for tweet in tweets[:15]:
    print(tweet.text)
    print()

ちょっと解説)
API Setup    : 色々書き方がありますが、これが一番、直接的でわかりやすいです。
user_timeline() : tweepyでデータを取得するメソッドです。 最新の20個のデータを取得できます。

API.home_timeline([since_id][, max_id][, count][, page])
が文法になります。(http://docs.tweepy.org/en/3.7.0/api.html)

このapp.pyを実行すると、

*自分のPCはwindowsなので、コマンドラインから、(venv)を起動してapp.pyを実行しています。
venvの構築は、こちらの記事に。

#Output①
Number of tweets extracted: 30.

(取得するtweetにデータ形式エラーのものがあると、途中で処理が終わってしまうそうです。 これは別途対応します。)


#Output②
The Great State of Tennessee is so close to passing School Choice. All of our Na
tion’s children, regardless of back… https://t.co/waTxCBpsMD

.@SenMikeLee of the great state of Utah has written a wonderful new book entitle
d, “Our Lost Declaration.” Highly recommended!
As ONE UNITED NATION, we will work, we will pray, and we will fight for the day
when every family across our land c… https://t.co/IcjJfEnaE1
Today, @FLOTUS Melania and I were honored to join thousands of leaders from acro
ss the Country for the 2019 Prescri… https://t.co/t9bRwNnIy9

これは、tweepyで取得されたオブジェクトの中で、text属性を指定して表示したものです。



さて、この.text属性のデータの他にも、多くの属性データが取得されています。

このuser_timeline()で取得したObjectのタイプは、

>>> type(tweets)
<class 'tweepy.models.ResultSet'>
https://stackoverflow.com/questions/42542327/how-to-extract-information-from-tweepy-resultset

'tweepy.models.ResultSet'は、リスト形式のiterableなデータです。


tweetsに格納された全データの取得
>>> print(tweets[0])

Status(_api=<tweepy.api.API object at 0x0000000007552278>, _json={'created_at': 'Fri Apr 26 22:
57:34 +0000 2019', 'id': 1121911223212285953, 'id_str': '1121911223212285953', 'text': 'THANK Y
OU @NRA! #NRAAM https://t.co/SWkpe1eFhT', 'truncated': False, 'entities': {'hashtags': [{'text'
: 'NRAAM', 'indices': [16, 22]}], 'symbols': [], 'user_mentions': [{'screen_name': 'NRA', 'name
': 'NRA', 'id': 21829541, 'id_str': '21829541', 'indices': [10, 14]}], 'urls': [], 'media': [{'
…果てしなく続くので以下省略

>>> type(tweets[0])

<class 'tweepy.models.Status'>

格納されているデータをDictionary形式に変換
>>> tweets[0] .__dict__
{'_api': <tweepy.api.API object at 0x0000000007552278>, '_json': {'created_at': 'Fri Apr 26 22:
57:34 +0000 2019', 'id': 1121911223212285953, 'id_str': '1121911223212285953', 'text': 'THANK Y
OU @NRA! #NRAAM
https://t.co/SWkpe1eFhT'
, 'truncated': False, 'entities': {'hashtags': [{'text'
: 'NRAAM', 'indices': [16, 22]}], 'symbols': [], 'user_mentions': [{'screen_name': 'NRA', 'name

…果てしなく続くので以下省略


DictionaryデータのKeyを取得

>>> tweets[0] .__dict__ .keys()
dict_keys(['_api', '_json', 'created_at', 'id', 'id_str', 'text', 'truncated', 'entities', 'extended_entities', 'source', 'source_url', 'in_reply_to_status_id', 'in_reply_to_status_id_str','in_reply_to_user_id', 'in_reply_to_user_id_str', 'in_reply_to_screen_name', 'author', 'user','geo', 'coordinates', 'place', 'contributors', 'is_quote_status', 'retweet_count', 'favorite_count', 'favorited', 'retweeted', 'possibly_sensitive', 'lang'])

又は

>>>print(dir(tweets[0]))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_api', '_json', 'author', 'contributors', 'coordinates', 'created_at', 'destroy', 'entities', 'favorite', 'favorite_count', 'favorited', 'geo', 'id', 'id_str', 'in_reply_to_screen_name', 'in_reply_to_status_id', 'in_reply_to_status_id_str', 'in_reply_to_user_id', 'in_reply_to_user_id_str', 'is_quote_status', 'lang', 'parse', 'parse_list', 'place', 'retweet', 'retweet_count', 'retweeted', 'retweets', 'source', 'source_url', 'text', 'truncated', 'user']

そこで、これらの属性を指定して値を取得してみます。

 print(tweets[0].favorite_count)
76742
print(tweets[0].retweet_count)
18597

2. Pandasで取得したデータ構造を整理する

1) pandasのDataFrameを使って、表を作成します。


app.pyに以下の記述を追加。

data = pd.DataFrame(data=[tweet.text for tweet in tweets], columns=['Tweets'])
print(data)

Output

                                               Tweets
0   The Great State of Tennessee is so close to pa...
1   .@SenMikeLee of the great state of Utah has wr...
2   As ONE UNITED NATION, we will work, we will pr...
3   Today, @FLOTUS Melania and I were honored to j...
4   Rep. Alexandria Ocasio-Cortez is correct, the ...
5   I didn’t call Bob Costa of the Washington Post...
6   ....Congress has no time to legislate, they on...
7   No Collusion, No Obstruction - there has NEVER...
8   Can anyone comprehend what a GREAT job Border ...

・・・30個続いていますが省略
左の数字はindex.


2) Columnの追加

(参考:https://www.tutorialspoint.com/python_pandas/python_pandas_introduction.htm

app.py

data['len']  = np.array([len(tweet.text) for tweet in tweets])
data['ID']   = np.array([tweet.id for tweet in tweets])
data['Date'] = np.array([tweet.created_at for tweet in tweets])
data['Source'] = np.array([tweet.source for tweet in tweets])
data['Likes']  = np.array([tweet.favorite_count for tweet in tweets])
data['RTs']    = np.array([tweet.retweet_count for tweet in tweets])

print(data)


Output
                                               Tweets  len  ...   Likes    RTs
0   The Great State of Tennessee is so close to pa...  140  ...   77992  18832
1   .@SenMikeLee of the great state of Utah has wr...  126  ...   47258  11420
2   As ONE UNITED NATION, we will work, we will pr...  140  ...   60408  14881


Columnが追加されています。

色々とできそうです。

3)Columnの削除
data.drop(columns=['Likes','RTs'],inplace=True)



***** DataFrameの取り扱い (DataFrame.values )*****


# importing pandas as pd
import pandas as pd
  
# Creating the DataFrame
df = pd.DataFrame({"A":[12, 4, 5, None, 1], 
                   "B":[7, 2, 54, 3, None], 
                   "C":[20, 16, 11, 3, 8], 
                   "D":[14, 3, None, 2, 6]}) 
  
# Print the DataFrame
print(df)


Output

   Weight    Name  Age
0      45     Sam   14
1      88  Andrea   25
2      56    Alex   55
3      15   Robin    8
4      71     Kia   21

print(df.values)

Output

[[45 'Sam' 14]
 [88 'Andrea' 25]
 [56 'Alex' 55]
 [15 'Robin' 8]
 [71 'Kia' 21]]

print(df.values[0])
[45 'Sam' 14]

print(df.values[0][1])
Sam


◇pandas dataframeに格納されたデータのタイプ
print(df.dtypes)

Date     datetime64[ns]
ID                int64
Like              int64
Tweet            object
Date2            object
dtype: object

(参考)
https://www.geeksforgeeks.org/python-pandas-dataframe-values/



最終的なまとめ

app.py


import tweepy           # To consume Twitter's API
import pandas as pd     # To handle data
import numpy as np      # For number computing

# We import our access keys:
from credentials import *    # This will allow us to use the keys as variables
# API's setup:
def twitter_setup():
    """
    Utility function to setup the Twitter's API
    with our access keys provided.
    """
    # Authentication and access using keys:
    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    # Return API with authentication:
    api = tweepy.API(auth)
    return api

    # We create an extractor object:

extractor = twitter_setup()
    # We create a tweet list as follows:

tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=30)

print("Number of tweets extracted: {}.\n".format(len(tweets)))

for tweet in tweets[:30]:
    print(tweet.text)
    print()

#Creating a (pandas) DataFrame
data = pd.DataFrame(data=[tweet.text for tweet in tweets], columns=['Tweets'])

print(data)
print(data.head(10))

print(data.tail(10))
print(dir(tweets[0]))
print(tweets[0].favorite_count)
print(tweets[0].retweet_count)

data['len']  = np.array([len(tweet.text) for tweet in tweets])
data['ID']   = np.array([tweet.id for tweet in tweets])
data['Date'] = np.array([tweet.created_at for tweet in tweets])
data['Source'] = np.array([tweet.source for tweet in tweets])
data['Likes']  = np.array([tweet.favorite_count for tweet in tweets])
data['RTs']    = np.array([tweet.retweet_count for tweet in tweets])

print(data)

 # We extract the tweet with more FAVs and more RTs:

fav_max = np.max(data['Likes'])
rt_max  = np.max(data['RTs'])

fav = data[data.Likes == fav_max].index[0]
rt  = data[data.RTs == rt_max].index[0]

 # Max FAVs:
print("The tweet with more likes is: \n{}".format(data['Tweets'][fav]))
print("Number of likes: {}".format(fav_max))
print("{} characters.\n".format(data['len'][fav]))

 # Max RTs:
print("The tweet with more retweets is: \n{}".format(data['Tweets'][rt]))
print("Number of retweets: {}".format(rt_max))
print("{} characters.\n".format(data['len'][rt]))


(output)

Number of tweets extracted: 30.
The Great State of Tennessee is so close to passing School Choice. All of our Na
tion’s children, regardless of back… https://t.co/waTxCBpsMD
.@SenMikeLee of the great state of Utah has written a wonderful new book entitle
d, “Our Lost Declaration.” Highly recommended!
As ONE UNITED NATION, we will work, we will pray, and we will fight for the day
when every family across our land c… https://t.co/IcjJfEnaE1
Today, @FLOTUS Melania and I were honored to join thousands of leaders from acro
ss the Country for the 2019 Prescri… https://t.co/t9bRwNnIy9
Rep. Alexandria Ocasio-Cortez is correct, the VA is not broken, it is doing grea
t. But that is only because of the… https://t.co/2XHTS0gNl9
I didn’t call Bob Costa of the Washington Post, he called me (Returned his call
)!  Just more Fake News.
....Congress has no time to legislate, they only want to continue the Witch Hunt
, which I have already won. They sh… https://t.co/SR99p1tb72
No Collusion, No Obstruction - there has NEVER been a President who has been mor
e transparent. Millions of pages of… https://t.co/v8HpsttkC5
Can anyone comprehend what a GREAT job Border Patrol and Law Enforcement is doin
g on our Southern Border. So far th… https://t.co/G13GJJCTeV
.....are there no “High Crimes and Misdemeanors,” there are no Crimes by me at
 all. All of the Crimes were committe… https://t.co/CfcpFiyym7
The Mueller Report, despite being written by Angry Democrats and Trump Haters, a
nd with unlimited money behind it (… https://t.co/P0Xq2h0Boq
Mexico’s Soldiers recently pulled guns on our National Guard Soldiers, probably
 as a diversionary tactic for drug s… https://t.co/bpPOy93S7x
A very big Caravan of over 20,000 people started up through Mexico. It has been
reduced in size by Mexico but is st… https://t.co/xoErbSRTwA
The American people deserve to know who is in this Country. Yesterday, the Supre
me Court took up the Census Citizen… https://t.co/xrFCfBHsXj
“Former CIA analyst Larry Johnson accuses United Kingdom Intelligence of helpin
g Obama Administration Spy on the 20… https://t.co/ShzvQun68s
Thanks Rush! @FoxNews https://t.co/x8XogwA8VX
You mean the Stock Market hit an all-time record high today and they’re actuall
y talking impeachment!? Will I ever… https://t.co/Z8CfnRuMy7
Great meeting this afternoon at the @WhiteHouse with @Jack from @Twitter. Lots o
f subjects discussed regarding thei… https://t.co/Sw2ZwrclUT
I will be in Green Bay, Wisconsin this Saturday, April 27th at the Resch Center
— 7:00pm (CDT). Big crowd expected!… https://t.co/4O8qSG4CYp
Great golf champion &amp; friend, Ernie Els (@TheBig_Easy), has done a tremendou
s job in assisting those w/ Autism thro… https://t.co/RimZI6BXKC
Great interview by Jared. Nice to have extraordinarily smart people serving our
Country! https://t.co/d6Tgrn4Tzn
KEEP AMERICA GREAT!
The Wall is being rapidly built! The Economy is GREAT! Our Country is Respected
again!
.....But should be much higher than that if Twitter wasn’t playing their politi
cal games. No wonder Congress wants… https://t.co/e1I3vgV1Ug
“The best thing ever to happen to Twitter is Donald Trump.” @MariaBartiromo  S
o true, but they don’t treat me well… https://t.co/5jwDvocFqG
“Harley Davidson has struggled with Tariffs with the EU, currently paying 31%.
They’ve had to move production overs… https://t.co/r0RAX6jBHU
....Dumb and Sick. A really bad show with low ratings - and will only get worse.
 CNN has been a proven and long ter… https://t.co/owlRr5I3P6
Sorry to say but @foxandfriends is by far the best of the morning political show
s on television. It rightfully has… https://t.co/SpyApUgKBK
In the “old days” if you were President and you had a good economy, you were b
asically immune from criticism. Remem… https://t.co/lRBKqFnFle
The Radical Left Democrats, together with their leaders in the Fake News Media,
have gone totally insane! I guess t… https://t.co/m87QJerN6a


                                               Tweets
0   The Great State of Tennessee is so close to pa...
1   .@SenMikeLee of the great state of Utah has wr...
2   As ONE UNITED NATION, we will work, we will pr...
3   Today, @FLOTUS Melania and I were honored to j...
4   Rep. Alexandria Ocasio-Cortez is correct, the ...
5   I didn’t call Bob Costa of the Washington Post...
6   ....Congress has no time to legislate, they on...
7   No Collusion, No Obstruction - there has NEVER...
8   Can anyone comprehend what a GREAT job Border ...
9   .....are there no “High Crimes and Misdemeanor...
10  The Mueller Report, despite being written by A...
11  Mexico’s Soldiers recently pulled guns on our ...
12  A very big Caravan of over 20,000 people start...
13  The American people deserve to know who is in ...
14  “Former CIA analyst Larry Johnson accuses Unit...
15      Thanks Rush! @FoxNews https://t.co/x8XogwA8VX
16  You mean the Stock Market hit an all-time reco...
17  Great meeting this afternoon at the @WhiteHous...
18  I will be in Green Bay, Wisconsin this Saturda...
19  Great golf champion &amp; friend, Ernie Els (@...
20  Great interview by Jared. Nice to have extraor...
21                                KEEP AMERICA GREAT!
22  The Wall is being rapidly built! The Economy i...
23  .....But should be much higher than that if Tw...
24  “The best thing ever to happen to Twitter is D...
25  “Harley Davidson has struggled with Tariffs wi...
26  ....Dumb and Sick. A really bad show with low ...
27  Sorry to say but @foxandfriends is by far the ...
28  In the “old days” if you were President and yo...
29  The Radical Left Democrats, together with thei...


                                              Tweets
0  The Great State of Tennessee is so close to pa...
.@SenMikeLee of the great state of Utah has wr...
2  As ONE UNITED NATION, we will work, we will pr...
3  Today, @FLOTUS Melania and I were honored to j...
4  Rep. Alexandria Ocasio-Cortez is correct, the ...
5  I didn’t call Bob Costa of the Washington Post...
6  ....Congress has no time to legislate, they on...
7  No Collusion, No Obstruction - there has NEVER...
8  Can anyone comprehend what a GREAT job Border ...
9  .....are there no “High Crimes and Misdemeanor...


                                              Tweets
0  The Great State of Tennessee is so close to pa...
.@SenMikeLee of the great state of Utah has wr...
2  As ONE UNITED NATION, we will work, we will pr...
3  Today, @FLOTUS Melania and I were honored to j...
4  Rep. Alexandria Ocasio-Cortez is correct, the ...
5  I didn’t call Bob Costa of the Washington Post...
6  ....Congress has no time to legislate, they on...
7  No Collusion, No Obstruction - there has NEVER...
8  Can anyone comprehend what a GREAT job Border ...
9  .....are there no “High Crimes and Misdemeanor...
                                               Tweets
20  Great interview by Jared. Nice to have extraor...
21                                KEEP AMERICA GREAT!
22  The Wall is being rapidly built! The Economy i...
23  .....But should be much higher than that if Tw...
24  “The best thing ever to happen to Twitter is D...
25  “Harley Davidson has struggled with Tariffs wi...
26  ....Dumb and Sick. A really bad show with low ...
27  Sorry to say but @foxandfriends is by far the ...
28  In the “old days” if you were President and yo...
29  The Radical Left Democrats, together with thei...


['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__form
at__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__in
it__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__
', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__st
r__', '__subclasshook__', '__weakref__', '_api', '_json', 'author', 'contributor
s', 'coordinates', 'created_at', 'destroy', 'entities', 'favorite', 'favorite_co
unt', 'favorited', 'geo', 'id', 'id_str', 'in_reply_to_screen_name', 'in_reply_t
o_status_id', 'in_reply_to_status_id_str', 'in_reply_to_user_id', 'in_reply_to_u
ser_id_str', 'is_quote_status', 'lang', 'parse', 'parse_list', 'place', 'retweet
', 'retweet_count', 'retweeted', 'retweets', 'source', 'source_url', 'text', 'tr
uncated', 'user']


77992


18832


                                               Tweets  len  ...   Likes    RTs
0   The Great State of Tennessee is so close to pa...  140  ...   77992  18832
1   .@SenMikeLee of the great state of Utah has wr...  126  ...   47258  11420
2   As ONE UNITED NATION, we will work, we will pr...  140  ...   60408  14881
3   Today, @FLOTUS Melania and I were honored to j...  140  ...   45652  11040
4   Rep. Alexandria Ocasio-Cortez is correct, the ...  139  ...   81781  18455
5   I didn’t call Bob Costa of the Washington Post...  103  ...   70328  15617
6   ....Congress has no time to legislate, they on...  140  ...  109192  27222
7   No Collusion, No Obstruction - there has NEVER...  140  ...   91252  21448
8   Can anyone comprehend what a GREAT job Border ...  140  ...   81792  19334
9   .....are there no “High Crimes and Misdemeanor...  140  ...   75596  20328
10  The Mueller Report, despite being written by A...  140  ...   92288  22773
11  Mexico’s Soldiers recently pulled guns on our ...  140  ...  117837  31477
12  A very big Caravan of over 20,000 people start...  140  ...   81865  22350
13  The American people deserve to know who is in ...  140  ...  117294  26245
14  “Former CIA analyst Larry Johnson accuses Unit...  140  ...   99288  32467
15      Thanks Rush! @FoxNews https://t.co/x8XogwA8VX   45  ...   83279  25392
16  You mean the Stock Market hit an all-time reco...  139  ...  147051  34128
17  Great meeting this afternoon at the @WhiteHous...  140  ...   72291  19238
18  I will be in Green Bay, Wisconsin this Saturda...  140  ...   58720  15744
19  Great golf champion &amp; friend, Ernie Els (@...  144  ...   67200  14309
20  Great interview by Jared. Nice to have extraor...  112  ...   59134  13678
21                                KEEP AMERICA GREAT!   19  ...  161004  31272
22  The Wall is being rapidly built! The Economy i...   86  ...  141458  27744
23  .....But should be much higher than that if Tw...  139  ...   70032  16713
24  “The best thing ever to happen to Twitter is D...  139  ...   83959  20241
25  “Harley Davidson has struggled with Tariffs wi...  140  ...   68667  16352
26  ....Dumb and Sick. A really bad show with low ...  140  ...   76628  16914
27  Sorry to say but @foxandfriends is by far the ...  139  ...   75825  17264
28  In the “old days” if you were President and yo...  140  ...  149719  31420
29  The Radical Left Democrats, together with thei...  140  ...   68631  16774


[30 rows x 7 columns]

The tweet with more likes is:
KEEP AMERICA GREAT!
Number of likes: 161004
19 characters.


The tweet with more retweets is:
You mean the Stock Market hit an all-time record high today and they’re actuall
y talking impeachment!? Will I ever… https://t.co/Z8CfnRuMy7
Number of retweets: 34128
139 characters.


user_timeline()で取得できるValueの確認

tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=30)

>>> type(tweets)
<class 'tweepy.models.ResultSet'>

'author', 'contributors', 'coordinates', 'created_at', 'destroy', 'entities', 'favorite', 'favorite_count', 'favorited', 'geo', 'id', 'id_str', 'in_reply_to_screen_name', 'in_reply_to_status_id', 'in_reply_to_status_id_str', 'in_reply_to_user_id', 'in_reply_to_user_id_str', 'is_quote_status', 'lang', 'parse', 'parse_list', 'place', 'retweet', 'retweet_count', 'retweeted', 'retweets', 'source', 'source_url', 'text', 'truncated', 'user']
◇ author
0  User(_api=<tweepy.api.API object at 0x00000000...
1  User(_api=<tweepy.api.API object at 0x00000000...
2  User(_api=<tweepy.api.API object at 0x00000000...

◇ created_at
0 2019-04-30 01:23:49
1 2019-04-30 01:17:20

◇ entities
0  {'hashtags': [], 'symbols': [], 'user_mentions...
1  {'hashtags': [], 'symbols': [], 'user_mentions...

◇favorite
0  <bound method Status.favorite of Status(_api=<...
1  <bound method Status.favorite of Status(_api=<...
2  <bound method Status.favorite of Status(_api=<...

◇favorite_count
0  60111
1  50856
2  50803

◇id
0  1123035192262823936
1  1123033559802023936
2  1123002475601170433

◇user
0  User(_api=<tweepy.api.API object at 0x00000000...
1  User(_api=<tweepy.api.API object at 0x00000000...
2  User(_api=<tweepy.api.API object at 0x00000000...

Cusror()でKey Wordを指定して、(且つ条件付きで) Tweetを取得する。

query ="Rugby World Cup"
count =10

tweets = tw.Cursor(api.search, q="Rugby World Cup min_faves:10 min_retweets:5 exclude:retweets",result_type="recent",                       include_entities="True",tweet_mode="extended", lang="en").items(count)

2019年4月15日月曜日

FLASK SQLAlchemy 基本のCRUDアプリ



まずは、基本のFlask/JinjaのPost Methodによるデータの受け渡しを以下のように作成し、
これをデータベース(Sqlite)に反映させるように、一つずつ加筆・修正していきます。



Flask/Jinja2 で htmlからPost Methodのデータを受け取る基本のアプリ。


app.py

from flask import Flask, render_template, redirect, request
app = Flask(__name__)
@app.route('/', methods=["GET", "POST"])
def home():
    if request.form:
        music = request.form['title']
    else:
        music = "Not yet entered"
    return render_template("music.html",music=music)
if __name__ == "__main__":
    app.run(debug=True)



templates/music.html

  <body>
    <form method="POST" action="/">
      <input type="text" name="title">
      <input type="submit" value="Add">
    </form>

<p>Now your inputs are as shown below</p>
{{music}}
  </body>
</html>

(スクリーン遷移イメージ)




*この記述の書き方を確認したい方は「Flask/Jinja2 GET/POST Method」にまとめてあります。





では、app.pyを以下のように変更します。

SQL Alchemyをインストールします。

# pip3 install --user flask sqlalchemy flask-sqlalchemy


次に、上記のファイルを、以下のように変更します

1) Create & Read





app.py

import os
from flask import Flask, render_template, redirect, request
from flask_sqlalchemy import SQLAlchemy

project_dir = os.path.dirname(os.path.abspath(__file__))
database_file = "sqlite:///{}".format(os.path.join(project_dir, "music.db"))

app = Flask(__name__)

app.config["SQLALCHEMY_DATABASE_URI"] = database_file

db = SQLAlchemy(app)

class Music(db.Model):

    title = db.Column(db.String(80), unique=True, nullable=False, primary_key=True)

    def __repr__(self):
        return "<Title: {}>".format(self.title)

@app.route('/', methods=["GET", "POST"])

def home():
    if request.form:
        music = Music(title=request.form.get("title"))
        db.session.add(music)  #データベースの作成と反映
        db.session.commit()
    musics = Music.query.all() #データベースの読み込み
    return render_template("music.html", musics=musics)

if __name__ == "__main__":
    app.run(debug=True)
 



templates/music.html

<html>
<body> 
 <h1>Add book</h1>
    <form method="POST" action="/">
        <input type="text" name="title">
        <input type="submit" value="Add">
    </form>

    <h1>Musics</h1>
    {% for music in musics %}
      <p>{{music.title}}</p>
    {% endfor %}

  </body>
</html>



DBを作る、
Windows PCで作業していますので、プロジェクト・ディレクトリをカレント・ディレクトリにした後で、
以下のコマンドを実行します。

>set FLASK_APP=app.py
>set FLASK_DEBUG=1
>flask shell

App: app [production]
Instance: C:\Users\ユーザ名\Desktop\newpy\20190415 SQLALCHemy\instance
>>> from app import db
>>> db.create_all()
>>> exit()

これで、DBがプロジェクト・フォルダ内に作成されました。

app.pyを起動させると、以下のように、データ・ベース・テーブルに、データが格納され、読み込みもできることが確認できます。







2019年4月12日金曜日

mod_wsgiで一気にFlask環境まで構築する

VPS環境にApcheをインストールして、mod_wsgi(Daemon Mode)でFlaskを動かせるようにするための設定を、一気に終わらせます。
 

 
 
1.  Apacheをインストールする。
1) 利用可能なhttpdの確認
[root@ofcm9och /]# yum list available | grep httpd
httpd.x86_64                              2.4.6-88.el7.centos            base
httpd-devel.x86_64                        2.4.6-88.el7.centos            base
httpd-manual.noarch                       2.4.6-88.el7.centos            base
httpd-tools.x86_64                        2.4.6-88.el7.centos            base
keycloak-httpd-client-install.noarch      0.6-3.el7                      base
libmicrohttpd.i686                        0.9.33-2.el7                   base
libmicrohttpd.x86_64                      0.9.33-2.el7                   base
libmicrohttpd-devel.i686                  0.9.33-2.el7                   base
libmicrohttpd-devel.x86_64                0.9.33-2.el7                   base
libmicrohttpd-doc.noarch                  0.9.33-2.el7                   base
python2-keycloak-httpd-client-install.noarch
 
2) httpdのインストール
# yum -y install httpd httpd-tools httpd-devel httpd-manual
Complete!
 
3)確認
[root@ofcm9och /]# yum list installed | grep httpd
httpd.x86_64                       2.4.6-88.el7.centos            @base
httpd-devel.x86_64                 2.4.6-88.el7.centos            @base
httpd-manual.noarch                2.4.6-88.el7.centos            @base
httpd-tools.x86_64                 2.4.6-88.el7.centos            @base
 
4)  再起動する。
# systemctl start httpd
 
5) 起動の状態を確認する。
$ systemctl status httpd
httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2018-12-24 23:32:33 JST; 23s ago
     Docs: man:httpd(8)
           man:apachectl(8)
Main PID: 1338 (httpd)
 
 
6) httpd自動起動の設定
$ systemctl enable httpd
 
7)自動起動設定の確認
$systemctl list-unit-files | grep httpd
httpd.service                                 enabled
 
2. SELinuxの無効化
 
1) 現状の確認
[root@ /]# sestatus
SELinux status:                 enabled
 
2Configファイルのコピーを保存。(??)
[root@ /]# cp -piv /etc/selinux/config /etc/selinux/config.`date "+%Y%m%d_%H%M%S "` ‘/etc/selinux/config’ -> ‘/etc/selinux/config.20181223’
 
 
3) Configファイルの修正
[root@ /]# cd  /etc/selinux/
[root@ selinux]# vi config
#SELINUX=enforcing
SELINUX=disabled
 
4) OSの再起動
[root@ selinux]#shutdown -r now
 
5)再確認
[root@ /]# sestatus
SELinux status:                 disabled
 
 
3. Firewallを設定する。
 
1) ファイアウォールが起動中かどうかを確認
# firewall-cmd --state
running
 
2) ファイアウォール設定を確認
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
 services: ssh dhcpv6-client
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
 
3) http/httpsのサービス追加
[root@ ~]# firewall-cmd --zone=public --add-service=http –permanent
success
[root@ ~]# firewall-cmd --zone=public --add-service=https --permanent
success
[root@ /]# firewall-cmd –reload
success
[root@ /]# firewall-cmd --list-all
  public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: ssh dhcpv6-client http https
  ports:       <- 後日、ポート番号を指定して解放する。
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
 
4. https通信に関する設定する。
 
1) mod_sslがインストールされているかの確認。
 (Loaded Modulesの確認): # httpd -M
 又は
 (Installed Packagesの確認): #yum list installed | grep mod_ssl
 
インストールされていないので、この段階では、両方とも、何も検知しない。
 
2) mod_sslのインストール
[root@ /]# yum install mod_ssl
Complete!
 
3)再起動で変更を反映します。
[root@ /]# systemctl restart httpd
 
4Loaded Modulesの確認
[root@ /]# httpd -M  
 ssl_module (shared)
 
https:// (IP address)で、ブラウザでも表示できることの確認)
 
5. Python3.7 pip のインストール
 
1) CentOSで必要なパッケージをインストールします。
# yum --setopt=group_package_types=mandatory,default,optional groupinstall "Development Tools"
#yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel python-devel libffi-devel
 
Complete!
#yum install httpd-devel python-devel
Package httpd-devel-2.4.6-88.el7.centos.x86_64 already installed and latest version Package python-devel-2.7.5-76.el7.x86_64 already installed and latest version Nothing to do
 
 
2) Pythonをソースからインストールする。
 
# cd /usr/local/src  ←このディレクトリに入れて管理することはとても大事。
 
 
でインストールしたいバージョンの確認。
 
[root@ofcm9och src]# yum -y install wget
 
[root@ofcm9och src]# ls -a
.  ..  Python-3.7.3.tgz
 
[root@ofcm9och src]# tar zxvf Python-3.7.3.tgz
([root@ofcm9och src]# tgz Python-3.7.3.tgz)
 
cd Python-3.7.3
[root@ueczshc7 Python-3.7.3]# ./configure --enable-shared
[root@ofcm9och Python-3.6.8]# ./configure --enable-optimizations <- Note1)
[root@ueczshc7 Python-3.7.3]# make && make altinstall
 
Collecting setuptools
Collecting pip
 
Installing collected packages: setuptools, pip
 
Successfully installed pip-19.0.3 setuptools-40.8.0
 
 
**Note 1) added on Jan.2019
何度か、ソースコードからpythonをビルドした時に気が付いたのだが、./configure --enable-shared を実行すると、「効率的なシステム構築の為に、 ./configure --enable-optimizations を実行することを合わせて考えてください。」というメッセージが出るので、実行していたが、このコマンドを実行すると、シェアド・ライブラリ用のファイル libpython3.7m.so が作成されないようだ。 wsgiは、shared library を使うことを強く推奨しているので、 ./configure --enable-optimizations は実行してはいけない。
 
 
3) シンボリックリンクを作成する。
 
[root@ofcm9och /]# cd /usr/local/bin
[root@ofcm9och bin]# ls -a
.   2to3-3.7          idle3.7  pydoc3.7   python3.7m         pyvenv-3.7
..  easy_install-3.7  pip3.7   python3.7  python3.7m-config
 
[root@ofcm9och /]# cd /usr/bin
[root@ofcm9och bin]# ls -a
python
ab                     gtroff                    python2
aclocal                gunzip                python2.7
aclocal-1.13           gzexe              python2.7-config
acpi_listen            gzip                 python2-config
addr2line              h2ph                python-config <- python3は無い。
 
 
(Symbolic Linkの作成:python3.7 (実在)にpython3というリンクを作る)
 
$ ln -s /usr/local/bin/python3.7 /usr/bin/python3
 
[root@ofcm9och bin]# ls -a
.                        gsoelim               pwmake
..                       gstack                  pwscore
[                        gtar                      pydoc
a2p                    gtbl                     python
ab                      gtroff                  python2
aclocal              gunzip                 python2.7
aclocal-1.13      gzexe                  python2.7-config
acpi_listen        gzip                     python2-config
addr2line           h2ph                   python3  <- 出来た。
 
この段階で、python3.7 とコマンドをうっても、起動できません。
以下のようなエラーになります。
[ ~]# python3.7
python3.7: error while loading shared libraries: libpython3.7m.so.1.0: cannot open shared object file: No such file or directory
 
[root@ofcm9och /]# cd /usr/local/lib
[root@ofcm9och lib]# ls -a
.   libpython3.7m.so      libpython3.so  python3.7
..  libpython3.7m.so.1.0  pkgconfig
 
[root@ofcm9och /]# find -name lib64
./usr/lib/debug/usr/lib64
./usr/lib/debug/lib64
./usr/lib64  <-ここにシンボリックファイルを作成する。
./usr/share/gdb/auto-load/usr/lib64
./usr/share/gdb/auto-load/lib64
./usr/local/lib64
./usr/src/kernels/3.10.0-957.10.1.el7.x86_64/arch/sh/lib64
./lib64
 
[root@ofcm9och /]$ ln -s /usr/local/lib/libpython3.7m.so.1.0 /lib64/
 
[root@ofcm9och /]# find -name libpython3.7m.so.1.0
./usr/lib64/libpython3.7m.so.1.0 <-出来た。
./usr/local/lib/libpython3.7m.so.1.0
./usr/local/src/Python-3.7.3/libpython3.7m.so.1.0
 
4) シンボリック・リンクが機能しているか確認
[root@ofcm9och /]# python3.7 –version
Python 3.7.3
 
[root@ueczshc7 /]# python3
Python 3.7.3 (default, Apr  9 2019, 02:55:23)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
 
[root@ueczshc7 /]# python3.7
Python 3.7.3 (default, Apr  9 2019, 02:55:23)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
 
[root@ofcm9och /]# which python <- pythonだけだとデフォルト
/usr/bin/python
[root@ofcm9och /]# python -V
Python 2.7.5
 
6. Virtualenvのインストール
pipでインストールします。 pipがインストールされているか、違うバージョンのpythonが既にインストールされているときのpipの実行の仕方など、こちらにまとめていますので、参考に。【 Python PIP  良く使うコマンド一覧 <https://mycodingjp.blogspot.com/2018/10/python-pip.html 】
 
[root@ueczshc7 /]# cd /home
[root@ueczshc7 home]#python3 -m pip install virtualenv  
Successfully installed virtualenv-16.4.3
 
グローバル環境にインストールされたpackageのリストの確認。
[root@ueczshc7 home]# python3 -m pip freeze
virtualenv==16.4.3
 
 
7. Virtual Environmentを作成する為のディレクトリー作成。
[root@ueczshc7 home]# mkdir venv_env
[root@ueczshc7 home]# virtualenv venv_env
Using base prefix '/usr/local'
New python executable in /home/venv_env/bin/python3
Also creating executable in /home/venv_env/bin/python
Installing setuptools, pip, wheel...
done.
 
 
7. 仮想環境(virtualenv)のアクティベート
[root@ueczshc7 home]# source venv_env/bin/activate
(venv_env) [root@ueczshc7 home]# which python
/home/venv_env/bin/python
(venv_env) [root@ueczshc7 home]# python -V
Python 3.7.3 <- virtualenvをインストールしたときのPython環境に準拠します。
(venv_env) [root@ueczshc7 home]# pip freeze
(venv_env) [root@ueczshc7 home]# <- インストールされたpackageはありません。
 
 
********************************************************************************
若し、cd /usr/local/src にインストールしたPython3の環境と別のPythonのバージョンをmod_wsgiで使用したい場合、この仮想化対象となるvenv_envフォルダ内に新しくインストールしても良い。
 
この場合、mod_wsgiをコンパイルする際に--with-python=/full/path/to/python で参照するPythonは、このインストールしたPython参照させる。
などによると、virtualenv(venv)環境下でmod_wsgiを利用する場合、virtualenvで使用するPythonのバージョンとmod_wsgiをコンパイルしたバージョンは同じでなくてはいけないらしい。 そうであれば、
 
 
********************************************************************************
 
8mod_wsgiをインストールする。
1) venv_env環境にインストールする。
 
[root@ueczshc7 venv_env]# wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.6.5.tar.gz            
2019-04-09 17:57:53 (1.10 MB/s) - ‘4.6.5.tar.gz’ saved [693825]
 
[root@ueczshc7 venv_env] # tar zxvf 4.6.5.tar.gz
[root@ueczshc7 venv_env]# cd /
 
[root@ueczshc7 /]# find -name apxs
./usr/bin/apxs
 
[root@ueczshc7 /]# cd /home
[root@ueczshc7 home]# source venv_env/bin/activate
 
(venv_env) [root@ueczshc7 home]# cd venv_env/mod_wsgi-4.6.5
(venv_env) [root@ueczshc7 mod_wsgi-4.6.5]#
 
(venv_env) [root@ueczshc7 mod_wsgi-4.6.5]# ./configure --with-apxs=/usr/bin/apxs --with-python=/usr/bin/python3 ←これは、cd /usr/local/srcにインストールしたPython
configure: creating ./config.status
config.status: creating Makefile
 
(venv_env) [root@ueczshc7 mod_wsgi-4.6.5]# make && make install
Libraries have been installed in:
    /usr/lib64/httpd/modules
chmod 755 /usr/lib64/httpd/modules/mod_wsgi.so <-後でmod_wsgi.soが、pythonshared libraryを使えているか確認します。
 

 
9Flaskをインストールする
1) Install
この段階で、virtualenv 環境で実行されるPIPを確認すると、
(venv_env) [root@ueczshc7 mod_wsgi-4.6.5]# pip -V
pip 19.0.3 from /home/venv_env/lib/python3.7/site-packages/pip (python 3.7)
 
venv_envのサイトパッケージに格納されていることが分かる。
 
 
(venv_env) [root@ueczshc7 mod_wsgi-4.6.5]# pip install flask==
Collecting flask==
(venv_env) [root@ueczshc7 mod_wsgi-4.6.5]# pip install flask==1.0.2
Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0
 
2)確認
(venv_env) [root@ueczshc7 mod_wsgi-4.6.5]# pip freeze
Click==7.0
Flask==1.0.2
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
Werkzeug==0.15.2
 
(venv_env) [root@ueczshc7 venv_env]# which flask
/home/venv_env/bin/flask
 

 
以下のコマンドで、venv_env配下のsite-packageに、Flask関連のパッケージがインストールされた事が確認できる。
(venv_env) [root@ueczshc7 venv_env]# ls -a lib/python3.7/site-packages
 
.                    Flask-1.0.2.dist-info         MarkupSafe-1.1.1.dist-info  setuptools-41.0.0.dist-info
..                   itsdangerous                  pip                         werkzeug
click                itsdangerous-1.1.0.dist-info  pip-19.0.3.dist-info        Werkzeug-0.15.2.dist-info
Click-7.0.dist-info  jinja2                        pkg_resources               wheel
easy_install.py      Jinja2-2.10.1.dist-info       __pycache__                 wheel-0.33.1.dist-info
flask                markupsafe                    setuptools
 
11VirtualHostの設定
1httpd.confに、virtualhostを使うことの宣言
記載する場所はどこでも可だが、とりあえず 'Listen 80'の下に書く。
NameVirtualHost *:80
 
2) Virtual Hostの記述
LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so
<VirtualHost *:80>
   ServerName uslife.mossymob.tk
   DocumentRoot /var/uslife/html
 
   <Directory /var/uslife/html>
    Require all granted
   </Directory>
 
WSGIDaemonProcess forum user=apache group=apache python-home=/home/venv_env/
   WSGIScriptAlias /app/forum /var/uslife/html/app/forum/app.wsgi
 
   <Directory /var/uslife/html/app/forum>
   WSGIProcessGroup forum
   WSGIApplicationGroup %{GLOBAL}
   Require all granted
   </Directory>
     CustomLog /home/venv_env/access.log common
     ErrorLog /home/venv_env/error.log
     LogLevel info
</VirtualHost>
 
 
 
 
12. Project Fileのアップロード
[root@ueczshc7 /] # mkdir /var/uslife
[root@ueczshc7 /] # cd  /var/uslife
[root@ueczshc7 uslife]# mkdir html
[root@ueczshc7 uslife]# mkdir html/app
[root@ueczshc7 uslife]# mkdir html/app/forum
 
 
[root@ueczshc7 uslife]# ls -a /home/venv_env/bin
 
app/forum/app.wsgi
# coding: utf-8
activate_this ='/home/venv_env/bin/activate_this.py'
 
with open(activate_this) as file_:
    exec(file_.read(),dict(__file__=activate_this))
 
import sys
sys.path.insert(0, '/var/uslife/html/app/forum')
 
from app import app as application

app/forum/app.py

from flask import Flask,render_template,request
app = Flask(__name__)

@app.route('/app') <- pyファイルの名前がindex.pyではない場合、ファイル名 
def index():
    message="Hi, there!"
    return render_template("sample01.html", message=message)
   
@app.route('/add',methods=['POST'])
def add():
    if request.method =='POST':
        result = request.form['new_num']
    #else:
    #    result = "No wish! Ah?"
       
    return render_template("sample02.html", result=result)

if __name__ == '__main__':
    app.run()

app/forum/templates/sample01.html

<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>
 {{message}}
<form action="/app/forum/add" method="post">   <-Document Rootからのフルパス
<p>Input the number you like:</p>
<input type="text" name="new_num" >
<input type="submit" value="Do">
</form>
 </body>
</html>

app/forum/templates/sample02.html
<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>

<p>Now we know the number you like is</p>
{{result}}
 </body>
</html>


おしまい。