Opinion Mining / Sentiment Analysis (sebagian besar
researcher menganggap dua istilah ini sama/interchangeable) merupakan sebuah
cabang penelitian di domain Text Mining yang mulai booming pada awal tahun
2002-an. Riset-nya mulai marak semenjak paper dari B.Pang dan L.Lee [1] keluar.
Secara umum, Sentiment analysis ini dibagi menjadi 2 kategori besar :
1. Coarse-grained
sentiment analysis
2. Fined-grained
sentiment analysis
Coarse-grained sentiment analysis - kita mencoba
melakukan proses analysis pada level Dokumen. Singkatnya adalah kita mencoba
mengklasifikasikan orientasi sebuah dokumen secara keseluruhan. Orientasi ini
ada 3 jenih : Positif, Netral, Negatif. Akan tetapi, ada juga yang menjadikan nilai
orientasi ini bersifat kontinu / tidak diskrit.
Fined-grained sentiment analysis - kategori kedua
ini yang sedang Naik Daun sekarang. Maksudnya adalah para researcher sebagian
besar fokus pada jenis ini. Obyek yang ingin diklasifikasi bukan berada pada
level dokumen melainkan sebuah kalimat pada suatu dokumen.
Berikut dibawah ini merupakan tahapan dalam
pembuatan sentiment analyst menggunakan Bahasa pemrograman python.
1. Pada
pembuatan program kali ini memakai python versi 3.6.4
import os
import sys
import time
import json
import requests
import argparse
import lxml.html
import re
from textblob import TextBlob
from lxml.cssselect import CSSSelector
YOUTUBE_COMMENTS_URL = 'https://www.youtube.com/watch?v={youtube_id}'
YOUTUBE_COMMENTS_AJAX_URL =
'https://www.youtube.com/comment_ajax'
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1;
WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116
Safari/537.36'
np = 0
nn = 0
n = 0
def clean_text(text_sel):
return
' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)",
" ", text_sel).split())
def find_value(html, key, num_chars=2):
pos_begin = html.find(key) + len(key) + num_chars
pos_end = html.find('"', pos_begin)
return html[pos_begin: pos_end]
def extract_comments(html):
global np, n, nn
tree = lxml.html.fromstring(html)
item_sel = CSSSelector('.comment-item')
text_sel = CSSSelector('.comment-text-content')
time_sel = CSSSelector('.time')
author_sel = CSSSelector('.user-name')
for item in item_sel(tree):
analysis = TextBlob(clean_text(text_sel(item)[0].text_content()))
# set sentiment
if analysis.sentiment.polarity > 0:
result = 'positive'
np += 1
elif analysis.sentiment.polarity == 0:
result = 'neutral'
n += 1
else:
result = 'negative'
nn += 1
yield {'cid': item.get('data-cid'),
'text':
text_sel(item)[0].text_content(),
'time':
time_sel(item)[0].text_content().strip(),
'author':
author_sel(item)[0].text_content(),
'result': result}
def extract_reply_cids(html):
tree = lxml.html.fromstring(html)
sel = CSSSelector('.comment-replies-header > .load-comments')
return [i.get('data-cid') for i in sel(tree)]
def ajax_request(session, url, params,
data, retries=10, sleep=20):
for _ in range(retries):
response = session.post(url, params=params, data=data)
if response.status_code == 200:
response_dict = json.loads(response.text)
return response_dict.get('page_token', None),
response_dict['html_content']
else:
time.sleep(sleep)
def download_comments(youtube_id,
sleep=1):
session = requests.Session()
session.headers['User-Agent'] = USER_AGENT
# Get Youtube page with initial comments
response = session.get(YOUTUBE_COMMENTS_URL.format(youtube_id=youtube_id))
html = response.text
reply_cids = extract_reply_cids(html)
ret_cids = []
for comment in extract_comments(html):
ret_cids.append(comment['cid'])
yield comment
page_token = find_value(html, 'data-token')
session_token = find_value(html, 'XSRF_TOKEN', 4)
first_iteration = True
# Get remaining comments (the same as pressing the 'Show more' button)
while page_token:
data = {'video_id': youtube_id,
'session_token': session_token}
params = {'action_load_comments': 1,
'order_by_time': True,
'filter': youtube_id}
if first_iteration:
params['order_menu'] = True
else:
data['page_token'] = page_token
response = ajax_request(session, YOUTUBE_COMMENTS_AJAX_URL, params,
data)
if not response:
break
page_token, html = response
reply_cids += extract_reply_cids(html)
for comment in extract_comments(html):
if comment['cid'] not in ret_cids:
ret_cids.append(comment['cid'])
yield comment
first_iteration = False
time.sleep(sleep)
# Get replies (the same as pressing the 'View all X replies' link)
for cid in reply_cids:
data = {'comment_id': cid,
'video_id': youtube_id,
'can_reply': 1,
'session_token': session_token}
params = {'action_load_replies': 1,
'order_by_time': True,
'filter': youtube_id,
'tab': 'inbox'}
response = ajax_request(session, YOUTUBE_COMMENTS_AJAX_URL, params,
data)
if not response:
break
_, html = response
for comment in extract_comments(html):
if comment['cid'] not in ret_cids:
ret_cids.append(comment['cid'])
yield comment
time.sleep(sleep)
def main(argv):
global np, n, nn
parser = argparse.ArgumentParser(add_help=False, description=('Download
Youtube comments without using the Youtube API'))
parser.add_argument('--help', '-h', action='help',
default=argparse.SUPPRESS, help='Show this help message and exit')
parser.add_argument('--youtubeid', '-y', help='ID of Youtube video for
which to download the comments')
parser.add_argument('--output', '-o', help='Output filename (output
format is line delimited JSON)')
parser.add_argument('--limit', '-l', type=int, help='Limit the number of
comments')
try:
args = parser.parse_args(argv)
youtube_id = args.youtubeid
output = args.output
limit = args.limit
if not youtube_id or not output:
parser.print_usage()
raise ValueError('you need to specify
a Youtube ID and an output filename')
print('Downloading Youtube comments for video:', youtube_id)
count = 0
with open(output, 'w') as fp:
for comment in download_comments(youtube_id):
print(json.dumps(comment),
file=fp)
count += 1
sys.stdout.write('Downloaded %d
comment(s)\r' % count)
sys.stdout.flush()
if limit and count >= limit:
break
print('\n\nPositive: ', float(np/(np+n+nn)*100), '%')
print('Negative: ', float(nn/(np+n+nn)*100), '%')
print('Neutral: ', float(n/(np+n+nn)*100), '%')
print('\nDone!')
except Exception as e:
print('Error:', str(e))
sys.exit(1)
if __name__ == "__main__":
main(sys.argv[1:])
3. Pastikan
sudah menginstall packages untuk program diatas.
a. pip
install requests
b. pip
install lxml
c. pip
install cssselect
d. pip
install textblob
4. Listing
program dibawah ini digunakan untuk mendeklarasikan beberapa url yang akan
diakses kedalam program dan beberapa variable untuk menampung nilai – nilai
dalam program.
YOUTUBE_COMMENTS_URL
= 'https://www.youtube.com/watch?v={youtube_id}'
YOUTUBE_COMMENTS_AJAX_URL
= 'https://www.youtube.com/comment_ajax'
USER_AGENT
= 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/48.0.2564.116 Safari/537.36'
np
= 0 #persentase positif
nn
= 0 #persentase negatif
n
= 0 #persentase netral
5.
def
extract_comments(html), berfungsi untuk
mengambil data-data komentar seperti penulis, waktu, dan komentar itu sendiri
berdasarkan response (html). Pada fungsi ini juga ditentukan apkah komentar itu
positif, nagatif, atau netral dengan TextBlob.
6.
def
extract_reply_cids(html), hampir sama dengan
fungsi sebelumnya hanya mengambil id reply
7.
def
download_comments(youtube_id, sleep=1),
berfungsi untuk membuat request session ke alamat URL youtube dan setelah
mendapat response, response tersebut dikirim ke fungsi extract_comments
8.
def
main(argv), fungsi yang pertama kali dijalankan
dengan beberapa argument, yaitu –youtubeid untuk meletakkan id youtube,
--output untuk meletakkan komentar kedalam file, --limit untuk membatasi
komentar yang didownload. Pada fungsi ini akan dijalankan fungsi download_comments yang nilai baliknya
akan dimasukkan kedalam file yang telah didefinisikan pada saat menjalankan
program ini (contoh: --output analisa.txt) , kemudian menghitung persentase
komentar positif, negative, dan netral.
Hasil



0 komentar:
Post a Comment