質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Chrome extension

Chrome拡張機能

Q&A

解決済

5回答

3644閲覧

webスクレイピングした内容をmecabで形態素分析

SoraSue

総合スコア30

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Chrome extension

Chrome拡張機能

0グッド

1クリップ

投稿2017/09/11 13:52

編集2017/09/12 10:51

###前提・実現したいこと
現在、chrome拡張機能を作っています。ユーザーが見たページのURLをサーバー側に送って、そのURL先のページの本文を抽出しそれをmecabで形態素分析したいです。

###発生している問題・エラーメッセージ
webから本文を抽出することと、自分で用意した例文を形態素分析し名詞をmysqlに送ることには成功しました。しかし、抽出した本文を形態素分析してmysqlに送ることがありません。
また、printすると以下のようなエラーが出ていました。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 2: invalid start byte

そこで、スクレイピングしたtextの型を調べてみましたが、str型で特に問題になるとは思えません。(形態素分析できた例文もstr型です。)
###該当のソースコード
pythonをcgiとして実行しました。

python

1#!/usr/local/bin/python3.6 2 3print("Content-Type: text/html; charset=UTF-8") 4print() 5 6import cgi 7import cgitb; cgitb.enable() 8import json 9#import bs4 10#import urllib.request, urllib.parse 11from readability.readability import Document 12import urllib 13import html2text 14import MeCab 15import mysql.connector 16import re 17 18form = cgi.FieldStorage() 19for key in form.keys(): 20 url = form.getvalue(key) 21 html = urllib.request.urlopen(url) 22 s = html.read() 23 article = Document(s).summary() 24 text = html2text.html2text(article) 25 text = text.strip("") 26 text = text.replace("http","") 27 text = text.replace("/","") 28 text = text.replace("[","") 29 text = text.replace("]","") 30 text = text.replace("%","") 31 text = text.replace(" ","") 32 text = text.replace("{","") 33 text = text.replace("}","") 34 text = text.replace("%","") 35 text = text.replace(":","") 36 text = text.replace("#","") 37 text = text.replace("*","") 38 text = text.replace("\n","") 39 text = text.replace("|","") 40 text = text.replace("-","") 41 text = text.replace(".","") 42 text = text.replace("?","") 43 text = text.replace("(","") 44 text = text.replace(")","") 45 text = text.replace("<","") 46 text = text.replace(">","") 47 text = text.replace("¥¥","") 48 text = text.replace("¥n","") 49 text = text.replace("1","") 50 text = text.replace("2","") 51 text = text.replace("3","") 52 text = text.replace("4","") 53 text = text.replace("5","") 54 text = text.replace("6","") 55 text = text.replace("7","") 56 text = text.replace("8","") 57 text = text.replace("9","") 58 text = text.replace("0","") 59 text = text.replace("@","") 60 text = text.replace("\◆","") 61 text = text.replace("◆","") 62 63 tagger = MeCab.Tagger('-d ./mecab-ipadic-neologd') 64 tagger.parse('') 65 input = text 66 result = tagger.parseToNode(input) 67 node = tagger.parseToNode(input) 68 target_parts_of_speech = ('名詞', ) 69 words = [] 70 print(node.feature) 71 while node: 72 if node.feature.split(',')[0] in target_parts_of_speech: 73 print(type(node.surface)) 74 words.append(node.surface) 75 node = node.next 76 word = ','.join(words) 77 config = { 78 'user': 'root', 79 'password': 'root', 80 'unix_socket': '/Applications/MAMP/tmp/mysql/mysql.sock', 81 'database': 'hoge', 82 'raise_on_warnings': True, 83 } 84 link = mysql.connector.connect(**config) 85 cursor = link.cursor() 86 87 cursor.execute('''insert into horizon (url,text) values (%s,%s)''', [url,word]) 88 link.commit() 89 90 cursor.execute("select * from horizon;") 91 for row in cursor.fetchall(): 92 print(row[0],row[1],row[2]) 93 94 cursor.close() 95 link.close()

###試したこと
スクレイピングしてきた情報には無駄な記号や空白がたくさんあり、text = ""に入れても文字列として認識されませんでした。そのため、replaceで文章をシンプルにするようにしてみたものの、まだmecabは反応してくれません。

###補足情報(言語/FW/ツール等のバージョンなど)
開発環境は以下の通りです。

  • macOS Sierra
  • python3
  • MAMP バージョン4.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coco_bauer

2017/09/12 01:58

Webからスクレイピングしてきた本文の例を示して頂けませんか? 抱えていらっしゃる問題は、その本文をmecabで形態素分析できるようにする方法が判らない事だと思いますが、webから抽出したデータって数十億以上のバリエーション(webページ)があるので一括りに扱う事は無理ですから。
SoraSue

2017/09/12 10:48

現在は主にwikipediaをスクレイピングしています。
guest

回答5

0

ベストアンサー

提示エラー0xbb in position 2より、レスポンスのHTMLデータにはUTF-8BOMが付加されていると思われます。
参考 : バイトオーダーマーク

そこでローカルサーバにてUTF-8BOM付.htmlを取得してみました。
HTTPレスポンスのHTML(バイナリデータ)にはBOMは含まれていますが
Document(s).summary()にてstrに変換後にはBOMはちゃんと外されているようです。
よって提示エラーは再現できませんでした。

再現できる取得元データ(URL)を提示されるとさらに検証できるかもしれません。

検証環境 : Win10, Python3.5.x, readability-lxml-0.6.2(+cssselect-1.0.1), html2text-2016.9.19、HTTPサーバはOS標準のIIS

utf8bom.html(utf-8 BOM付で保存)

<!DOCTYPE html> <html lang="ja-JP"> <head> <meta charset="utf-8"> <title>タイトル</title> </head> <body> 本文 </body> </html>

検証スクリプト

Python

1# -*- coding: utf-8 -*- 2import sys 3print(sys.getdefaultencoding()) 4print(sys.stdin.encoding) 5print(sys.stdout.encoding) 6 7import urllib.request 8url = 'http://localhost/utf8bom.html' 9 10html = urllib.request.urlopen(url) 11s = html.read() 12print(type(s)) 13print('s-----\n',repr(s)) 14 15from readability.readability import Document 16article = Document(s).summary() 17print(type(article)) 18print('article-----\n',repr(article)) 19 20import html2text 21text = html2text.html2text(article) 22print(type(text)) 23print('text-----\n',repr(text)) 24 25import MeCab 26tagger = MeCab.Tagger('-Ochasen') 27tagger.parse('') 28node = tagger.parseToNode(text) 29while node: 30 print( node.surface,node.feature) 31 node = node.next

実行結果

utf-8 cp932 cp932 <class 'bytes'> s----- b'\xef\xbb\xbf<!DOCTYPE html>\n<html lang="ja-JP">\n<head>\n<meta charset="utf-8">\n<title>\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\x88\xe3\x83\xab</title>\n</head>\n<body>\n\xe6\x9c\xac\xe6\x96\x87\n</body>\n</html>\n' <class 'str'> article----- '<body id="readabilityBody">\n本文\n</body>\n' <class 'str'> text----- '本文\n\n' pathname[C:\Program Files\Anaconda3\lib\site-packages\_MeCab.cp35-win_amd64.pyd] desc[('.cp35-win_amd64.pyd', 'rb', 3)] BOS/EOS,*,*,*,*,*,*,*,* 本文 名詞,一般,*,*,*,*,本文,ホンブン,ホンブン BOS/EOS,*,*,*,*,*,*,*,*

実行環境の違いについて追記

当回答のコメント欄にて提示されたprintエラーの原因についてですが、質問本文のエンコーディングと異なることから推測すると、CGI動作させ、その標準出力のエンコーディングUS-ASCIIが日本語に対応していないためだと思われます。
ここで、ターミナル(シェル)上とCGI上では標準出力のエンコーディングが異なる可能性が高いことにご注意ください。
その理由と解決方法(TextIOWrapperで標準出力を開き直す)は以下に記載されています。
[python3]デフォルト文字コードの指定(CGI実行時)
すなわち、ターミナルでは動作するのにCGIではエンコーディングエラーが発生するなどがありえます。

投稿2017/09/13 04:55

編集2017/09/14 01:31
can110

総合スコア38256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SoraSue

2017/09/13 11:23

わざわざ検証までしていただきありがとうございます!sysをimportしてcan110さんのコードと同じようにprint()してみました。(テストしたサイトはhttps://ja.wikipedia.org/wiki/%E7%A2%BA%E7%8E%87)すると、print(sys.stdin.encoding)とprint(sys.stdin.encoding)の結果はUS-ASCIIになっていました。また、print('article-----\n',repr(article))が最後まで実行されず、UnicodeEncodeError: 'ascii' codec can't encode characters in position 125-126: ordinal not in range(128)というエラーが出ました。どうすればいいでしょうか?
can110

2017/09/13 13:41

提示URL「確率」は当方環境では問題なく動作しました。環境(OS)の問題ですね。 標準入出力がUS-ASCIIなので日本語を含む文字列がprintで出力できない環境で実行しているようです。 とりあえずprintの代わりにloggerモジュールを利用すれば動作を確認できますが、手順などは分かりますか?
can110

2017/09/13 13:46

根本解決には、そのcgiを動作させている環境(macOS Sierra?)の標準入出力のエンコーディングをUS-ASCIIからUTF-8(=MeCabのエンコーディング)に変更する必要があります。当方macではないので具体的には分かりませんが。
SoraSue

2017/09/13 14:58

わかりました。根本解決の方を試みたいと思います。標準入出力のエンコーディングをUS-ASCIIからUTF-8に変更する際、下記のcoco_bauerさんの回答にあるページが参考になると思い実践してみました。しかし、相変わらずUnicodeEncodeError: 'ascii' codec can't encode characters in positionが出てしまいます。
can110

2017/09/14 01:25

macは分からないのですが、実行環境の違いについて追記しました。
SoraSue

2017/09/14 11:01

can110さんに追記していただいたページの内容通り、以下のコードを実行してみました。 import io,sys sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') すると、500エラーが出てしまいます。原因は何でしょうか?調べてみても直せませんでした。 何回も伺うことになってしまいすみません。
can110

2017/09/14 11:24

500エラーはWebサーバが返すエラーです。このエラーが発生する原因は、CGI動作させた.py内部で単純なシンタックスエラーも含め、何等かのpythonエラーが発生しているためです。 まずは問題を単純化するため、単純に「あいう」という固定の日本語を含むHTMLを返すCGIが動作するように環境を整える必要があります。現在の環境ではそれもできないと思われます。 そのため、別途質問を立てたほうがよいと思います。 その際、CGIを呼び出しているWebサーバソフトやOSなどの環境を明示する必要があります。 CGI動作についてはあまり詳しくないため、申し訳ありませんが、これ以上の回答ができません。
SoraSue

2017/09/14 12:33

単純なhtmlを作って形態素解析できるか試してみましたが、やはりutf-8 US-ASCII US-ASCII s----- b'\n\n\n\n\n\n\n\xe6\x9c\xac\xe6\x96\x87\n\n\n' article----- --> -->というようにarticleのところで止まってしまいました。もっと基礎的な環境設定に問題があるのかもしれません。  can110さん、どこまでも親切に対応していただきありがとうございました!エラーを乗り越えて、アプリを完成させてみせます!
can110

2017/09/14 13:50

難しくても、単純な問題に分割して解いていけば答えは必ず見つかるはずです。 がんばってください!(CGI関連はよく分からないけど…)
guest

0

解析したい文章を入れると動くのでしょうか?
それでしたらHTMLを闇雲にテキストに直すのではなくて、抜き出したい箇所にXPATHなりCSS PATHを使って取り出した方が良いかと思います

投稿2017/09/12 08:57

kero1209

総合スコア431

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SoraSue

2017/09/12 10:09

わかりました。あらかじめタグを指定してデータを絞ってみます。そこで質問があるのですが、ページごとに本文を表すタグというのをどうやって見分けられるでしょうか?
Tomak

2017/09/12 12:25

> ページごとに本文を表すタグというのをどうやって見分けられるでしょうか? 横から失礼します。 本文とはBody要素のことでしょうか?XPathならbody要素は「/html/body」です。Google Chromeのデバッグ(F12)のElementタブで知りたい要素を右クリックして「Copy>Copy XPath」を選択すると取り出したい要素のXPathを得られます。同じ選択肢にCSSセレクタの「Copy selector」もあります。 見当違いなこと言ってたらすみません。
kero1209

2017/09/12 12:46

Tomak さんの言うようにブラウザの機能で取るのが簡単です。あとはその要素にID やclassがついてればそれを使ってやると短くかけます。
SoraSue

2017/09/12 12:58

Tomakさん、kero1209さんありがとうございます。僕はどちらかというと、特定のサイトをスクレイピングしたいのではなく、様々な種類のサイトのスクレイピングをしたいです。また、今は本文抽出の精度を高める前に、まず精度が悪くてもいいから名詞だけをmecabで分析できるようにしたいです。説明が足りずすみませんでした。
guest

0

UnicodeDecodeErrorというエラーが出ているということでしたら、以下の記事に書かれている方法で解決できませんか?

Python スクリプト実行時に UnicodeDecodeError が出る場合の対処方法

投稿2017/09/13 00:59

coco_bauer

総合スコア6915

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SoraSue

2017/09/13 11:27

有益なサイトを教えていただきありがとうございます!リンク先の内容を行なってみましたが、何も変わりませんでした。具体的には、anacondaのpython3.6のsite-packagesの中にsitecustomize.pyを入れてみました。しかし、デフォルトエンコーディングは変わりませんでした。
coco_bauer

2017/09/14 00:38

pythonで、"import sys","sys.setdefaultencoding('utf-8')"の2コマンドを実行した後、"sys.getdefaultencoding()"を実行すると何が表示されますか?
SoraSue

2017/09/14 10:47

最初に、sys.setdefaultencoding('utf-8')をいれて実行すると、AttributeError: module 'sys' has no attribute 'setdefaultencoding'と出てきました。そこで、このコマンドを削除して実行してみると、"utf-8"と出力されました。
SoraSue

2017/09/14 10:58

関係あるかわかりませんが、print(sys.stdout.encoding)がサーバー(僕の場合MAMP)のデフォルトエンコーディングを表示すると聞いて実行してみましたところ、US-ASCIIと表示されました。
guest

0

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 2: invalid start byte

UTF-8にエンコードできない0xbbの文字コードが原因です。
この0xbbは、バイトオーダーといって、BOM付きのファイルなどを読み込んだりすると出力されます。
BOM以外にもNULL文字(\0)もかなり危険です。

普通はこのような制御文字コード([\x00-\x1f\x7f])は危険なので、reモジュールの正規表現を使って削除してからMecabで解析してみてはいかがでしょうか。

python

1#HTML文字列から制御コードを削除 2text = re.sub(r'[\x00-\x1f\x7f]+', '', text) 3 4#BOMを消すだけなら、下記のようにデコード→エンコードしてもOKです 5text = text.decode('utf_8_sig').encode('utf-8')

http://docs.python.jp/3.6/library/re.html#re.sub
http://docs.python.jp/3.6/library/stdtypes.html#str.encode

ただし、<pre>...</pre>のHTMLコードは改行が抜けると表示も崩れるので、HTMLをスクレイピングしたい場合は注意してください。

また、対象のWebサイトが不特定多数なのであれば、文字コードの問題もでてくると思われます。
最近のWebサイトはUTF-8ですが、Shift-JISやEUC-JPが文字コードのサイトもあります。外国語のサイトは更に膨大な量の文字コードになるのである程度仕様を決めなければなりません。(UTF-8のみなど)

投稿2017/09/12 13:38

編集2017/09/12 16:27
Tomak

総合スコア1652

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SoraSue

2017/09/12 14:05

バイトオーダーというのを初めて知りました!教えていただきありがとうございます!とりあえずhttp://d.hatena.ne.jp/zariganitosh/20150209/ascii_code_secrets にある「htmlエスケープ」というのを削除してみましたが、まだ動きません。また、[\x00-\x1f\x7f]も削除してみましたがダメでした。具体的に何を消せばいいのでしょうか?
guest

0

pythonはさっぱりなんですが、DB以外は参考になりそうなサイトを見つけたので、情報提供。

Pythonでつくる検索エンジン(Webクローラ, Mecab, MongoDB, Flask)

まあ、既にご存知かもしれませんが。

投稿2017/09/12 13:36

sazi

総合スコア25173

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SoraSue

2017/09/12 14:05

いいサイトを教えていただきありがとうございます!色々な面で僕とやりたいことが似ていました。参考にしてみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問