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

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

ただいまの
回答率

91.45%

  • MySQL

    4273questions

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

  • Python

    3590questions

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

  • Chrome extension

    73questions

    Chrome拡張機能

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

解決済

回答 5

投稿 2017/09/11 22:52 ・編集 2017/09/12 19:51

  • 評価
  • クリップ 1
  • VIEW 244

SoraSue

score 21

前提・実現したいこと

現在、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として実行しました。

#!/usr/local/bin/python3.6

print("Content-Type: text/html; charset=UTF-8")
print()

import cgi
import cgitb; cgitb.enable()
import json
#import bs4
#import urllib.request, urllib.parse
from readability.readability import Document
import urllib
import html2text
import MeCab
import mysql.connector
import re

form = cgi.FieldStorage()
for key in form.keys():
    url = form.getvalue(key)
    html = urllib.request.urlopen(url)
    s = html.read()
    article = Document(s).summary()
    text = html2text.html2text(article)
    text = text.strip("")
    text = text.replace("http","")
    text = text.replace("/","")
    text = text.replace("[","")
    text = text.replace("]","")
    text = text.replace("%","")
    text = text.replace(" ","")
    text = text.replace("{","")
    text = text.replace("}","")
    text = text.replace("%","")
    text = text.replace(":","")
    text = text.replace("#","")
    text = text.replace("*","")
    text = text.replace("\n","")
    text = text.replace("|","")
    text = text.replace("-","")
    text = text.replace(".","")
    text = text.replace("?","")
    text = text.replace("(","")
    text = text.replace(")","")
    text = text.replace("<","")
    text = text.replace(">","")
    text = text.replace("¥¥","")
    text = text.replace("¥n","")
    text = text.replace("1","")
    text = text.replace("2","")
    text = text.replace("3","")
    text = text.replace("4","")
    text = text.replace("5","")
    text = text.replace("6","")
    text = text.replace("7","")
    text = text.replace("8","")
    text = text.replace("9","")
    text = text.replace("0","")
    text = text.replace("@","")
    text = text.replace("\◆","")
    text = text.replace("◆","")

    tagger = MeCab.Tagger('-d ./mecab-ipadic-neologd')
    tagger.parse('')
    input = text
    result = tagger.parseToNode(input)
    node = tagger.parseToNode(input)
    target_parts_of_speech = ('名詞', )
    words = []
    print(node.feature)
    while node:
        if node.feature.split(',')[0] in target_parts_of_speech:
            print(type(node.surface))
            words.append(node.surface)
        node = node.next
    word = ','.join(words)
    config = {
      'user': 'root',
      'password': 'root',
      'unix_socket': '/Applications/MAMP/tmp/mysql/mysql.sock',
      'database': 'hoge',
      'raise_on_warnings': True,
    }
    link = mysql.connector.connect(**config)
    cursor = link.cursor()

    cursor.execute('''insert into horizon (url,text) values (%s,%s)''', [url,word])
    link.commit()

    cursor.execute("select * from horizon;")
    for row in cursor.fetchall():
        print(row[0],row[1],row[2])

    cursor.close()
    link.close()

試したこと

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

補足情報(言語/FW/ツール等のバージョンなど)

開発環境は以下の通りです。

  • macOS Sierra
  • python3
  • MAMP バージョン4.2
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • coco_bauer

    2017/09/12 10:58

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

    キャンセル

  • SoraSue

    2017/09/12 19:48

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

    キャンセル

回答 5

checkベストアンサー

+3

提示エラー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>

検証スクリプト

# -*- coding: utf-8 -*-
import sys
print(sys.getdefaultencoding())
print(sys.stdin.encoding)
print(sys.stdout.encoding)

import urllib.request
url = 'http://localhost/utf8bom.html'

html = urllib.request.urlopen(url)
s = html.read()
print(type(s))
print('s-----\n',repr(s))

from readability.readability import Document
article = Document(s).summary()
print(type(article))
print('article-----\n',repr(article))

import html2text
text = html2text.html2text(article)
print(type(text))
print('text-----\n',repr(text))

import MeCab
tagger = MeCab.Tagger('-Ochasen')
tagger.parse('')
node = tagger.parseToNode(text)
while node:
    print( node.surface,node.feature)
    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 13:55

編集 2017/09/14 10:31

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/13 20: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)というエラーが出ました。どうすればいいでしょうか?

    キャンセル

  • 2017/09/13 22:41

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

    キャンセル

  • 2017/09/13 22:46

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

    キャンセル

  • 2017/09/13 23:58

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

    キャンセル

  • 2017/09/14 10:25

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

    キャンセル

  • 2017/09/14 20: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エラーが出てしまいます。原因は何でしょうか?調べてみても直せませんでした。
    何回も伺うことになってしまいすみません。

    キャンセル

  • 2017/09/14 20:24

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

    キャンセル

  • 2017/09/14 21: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さん、どこまでも親切に対応していただきありがとうございました!エラーを乗り越えて、アプリを完成させてみせます!

    キャンセル

  • 2017/09/14 22:50

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

    キャンセル

+2

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

投稿 2017/09/12 17:57

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/12 19:09

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

    キャンセル

  • 2017/09/12 21:25

    > ページごとに本文を表すタグというのをどうやって見分けられるでしょうか?

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

    キャンセル

  • 2017/09/12 21:46

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

    キャンセル

  • 2017/09/12 21:58

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

    キャンセル

+1

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

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

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

投稿 2017/09/12 22:36

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/12 23:05

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

    キャンセル

+1

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で解析してみてはいかがでしょうか。

#HTML文字列から制御コードを削除
text = re.sub(r'[\x00-\x1f\x7f]+', '', text)

#BOMを消すだけなら、下記のようにデコード→エンコードしてもOKです
text = 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 22:38

編集 2017/09/13 01:27

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/12 23:05

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

    キャンセル

+1

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

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

投稿 2017/09/13 09:59

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/13 20:27

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

    キャンセル

  • 2017/09/14 09:38

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

    キャンセル

  • 2017/09/14 19:47

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

    キャンセル

  • 2017/09/14 19:58

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

    キャンセル

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

ただいまの回答率

91.45%

関連した質問

  • 解決済

    PythonでWebスクレイピングを行うと文字化けします。

    pythonでWebスクレイピングを行おうとしているのですが、出力が文字化けします。 下記のコードが文字化けしている出力です。sucraping_naver.pyのファイルを実行

  • 受付中

    pythonでmysqlconnectorを使う際

    pythonでmysqlを操作して、日本語を取り出しその後それをcsvに書き込みたいのですが、 res = cursor.fetchall() で取り出した後に、どこかで .

  • 解決済

    Python スクレイピング

    [実現したい事] Python/スクレイピング初心者です。毎日コツコツ勉強しています。 スクレイピングにてあるサイトからBeautifulsoupもしくは正規表現を使用して指定

  • 受付中

    形態素解析の結果の一部のみを抽出したい

    前提・実現したいこと csvファイルにある文章をPythonを経由してMeCabで形態素解析をしています。  結果を出力する際、特定の品詞(名詞、形容詞、接続詞)と原形だけ

  • 受付中

    形態素解析の結果の際pydotplus、graphvizの結果が白紙出力

    いつもお世話になっております。質問です。 実現したいこと 以下のコードの実行結果がgraph().jpgで出力されるが、真っ白で出力。 しかし画像サイズはそれぞれ別々のサイズで

  • 解決済

    pythonでMecabを利用した語彙解析がうまくできない。

    ●環境 ・Windows Edition:Windows 7 Professional  Service Pack 1 ・pythonバージョン:Python 3.6.2 (v3.

  • 解決済

    mecab 品詞 選択

    やりたいこと 選択したテキストファイル内の文章をmecabを用いて形態素解析し、 品詞(名詞、動詞など)を絞り込みたいと考えています。 現在、テキストファイルの文章を形態素解析する

  • 解決済

    mecabでセリフのみを抽出したい

    やりたいこと mecabを用いて入力したテキストファイルのセリフ部分(「」や『』で囲まれている部分)の 名詞(代名詞,非自立名詞,数,固有名詞を除く)を取り出して行列selsに格納

同じタグがついた質問を見る

  • MySQL

    4273questions

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

  • Python

    3590questions

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

  • Chrome extension

    73questions

    Chrome拡張機能