Example #1
0
  def _create_table(self, reviews: Tuple[ReviewInfo, ...]) -> str:
    """レビュー情報一覧から table 要素を作成する

    Args:
      reviews (Tuple[ReviewInfo, ...]): レビュー情報一覧

    Returns:
      table タグで囲まれたテキスト
    """
    thead = tag('thead', tag('tr', tag('th', *ReviewInfo._fields)))
    tr_content_list = list()
    for review_info in reviews:
      # レビュー文の処理
      review = review_info.review.replace('\n', '<br>')
      review_info = review_info._replace(review=review)

      if self.normalize_mode:
        review = normalize(review)

      # 列要素を作成
      td_content_list = [tag('td', info) for info in review_info]

      # 行要素を作成
      tr = organize_contents(td_content_list, 'tr')
      tr_content_list.append(tr)

    tbody = organize_contents(tr_content_list, 'tbody')
    table_content_list = [thead, tbody]
    table = organize_contents(
        table_content_list, 'table',
        class_='tablesorter tablesorter-{}'.format(TABLE_DESIGN),
        id=OLD_AND_NEW[1]
    )
    return table
Example #2
0
def _make_stars_texts(reviews: Tuple[ReviewInfo, ...],
                      stars_dist: StarsDistribution) -> Tuple[str, ...]:
  """星評価に関する表示テキストを作成する

  Args:
    reviews (Tuple[ReviewInfo, ...]): レビュー情報一覧
    stars_dist (StarsDistribution): 星評価分布

  Returns:
    星の数ごとの h3 要素一覧
  """
  # 星評価の整理
  reviews_df = pandas.DataFrame(reviews)
  key_dict = OrderedDict()
  for i, num_stars_field in enumerate(StarsDistribution._fields):
    key_dict[num_stars_field] = float(i + 1)

  divided_dict = OrderedDict()
  eval_star_query_fmt = 'star == {}'
  for num_stars_field, eval_star in key_dict.items():
    eval_star_query = eval_star_query_fmt.format(eval_star)
    num_stars_df = reviews_df.query(eval_star_query)['star']
    divided_dict[num_stars_field] = num_stars_df.count()

  star_to_text = OrderedDict()
  for num_stars_field, star_count in divided_dict.items():
    star_text = '{}:\t{}'.format(num_stars_field, star_count)
    num_stars = getattr(stars_dist, num_stars_field)
    if star_count != num_stars:  # レビューの数が元のものと異なると元の星評価の数も異なる
      star_text = '{} / {}'.format(star_text, num_stars)

    star_to_text[num_stars_field] = star_text

  star_texts = [tag('h3', v) for v in star_to_text.values()]
  return star_texts
Example #3
0
  def convert(self, map_jsonfile: Union[str, pathlib.Path]) -> str:
    """商品レビュー内の文を属性と星評価別に対応付けされた JSON ファイルを見やすいように html ファイルに変換

    Args:
      map_jsonfile (Union[str, pathlib.Path]): 対応付けの結果を格納した JSON ファイル

    Returns:
      html で記述されたテキスト
    """
    mapped_data = MappingResult.load(map_jsonfile)
    self.category = mapped_data.category

    # head コンテンツ
    product_name = mapped_data.product
    title = tag('title', product_name)
    head_content_list = [*self._head_contents, title]
    head = organize_contents(head_content_list, 'head')

    # body コンテンツ
    body = self._make_body_content(mapped_data)

    # html コンテンツ
    html_content_list = [head, body]
    html = organize_contents(html_content_list, 'html')
    html = DOC_TYPE + '\n' + html
    return html
Example #4
0
  def __init__(self, dic_dir: str):
    self.dic_dir = dic_dir
    self.__category = ''
    self._mapper = None

    js_file = JS_DIR / 'heatmap.js'
    css_file = CSS_DIR / 'heatmap.css'

    script_content = read_script(js_file)
    style_content  = read_script(css_file)

    meta_content = tag('meta', charset='UTF-8')
    jquery_script_content = tag('script', '', type='text/javascript', 
                                src=JQUERY_JS)
    js_script_content = tag('script', script_content, type='text/JavaScript')
    css_script_content = tag('style', style_content, type='text/css')
    self._head_contents = (meta_content,
                           jquery_script_content,
                           js_script_content,
                           css_script_content,)
Example #5
0
  def _convert_review_data_to_body_content(
      self, reviewdata: ReviewPageJSON) -> str:
    """レビューデータを html の body 要素に変換する

    Args:
      reviewdata (ReviewPageJSON): Amazon レビューデータ

    Returns:
      body タグで囲まれたテキスト
    """
    real_reviews  = reviewdata.real_reviews
    num_reviews_text = 'レビュー数:{}'.format(real_reviews)
    total_reviews = reviewdata.total_reviews
    if total_reviews != real_reviews:
      num_reviews_text = '{} / {}'.format(num_reviews_text, total_reviews)

    reviews = reviewdata.reviews
    h3_content_list = _make_stars_texts(reviews, reviewdata.stars_distribution)
    # <body>コンテンツの用意
    body_content_list = [
        tag('h1', reviewdata.product),
        tag('h2', tag('a', '商品レビューページ', href=reviewdata.link)),
        tag('h2', 'メーカー:{}'.format(reviewdata.maker)),
        tag('h2', '評価:{}'.format(reviewdata.average_stars)),
        tag('h2', num_reviews_text),
        *h3_content_list,
    ]

    # <table>コンテンツの用意
    table = self._create_table(reviews)

    # <body>コンテンツの再設定
    body_content_list.append(table)
    body = organize_contents(body_content_list, 'body')
    return body
Example #6
0
  def _itemize_text_by_attr_and_star(
      self, attr_to_star_map: Attr2StarMap, anchor_dict: AnchorDict
  ) -> Tuple[str, ...]:
    """属性と星評価別にレビュー文中の文を列挙する

    Args:
      attr_to_star_map (Attr2StarMap): 属性と星評価別にレビュー文中の文を格納した辞書
      anchor_dict (AnchorDict): 属性と星評価別にレビュー文の情報をまとめたリストとアンカーを格納した辞書

    Returns:
      列挙された文一覧
    """
    display_fmt = '{}:{}'
    enum_content_list = list()
    for en_attr in attr_to_star_map:
      attr = self._mapper.en2ja[en_attr]
      enum_content_list.append(tag('h2', attr, id=en_attr))
      for star_str, anchor_prop in anchor_dict[attr].items():
        link_id, review_text_info_list = anchor_prop
        star_disp = STAR_DISPLAY_DICT[star_str]
        enum_content_list.append(
            tag('h3', display_fmt.format(attr, star_disp), id=link_id))
        if review_text_info_list:
          li_content_list = list()
          for review_text_info in review_text_info_list:
            text = review_text_info.text
            summary = tag('summary', text)
            review = normalize(review_text_info.review)
            marked_text = tag('span', text, class_='sentence-marker')
            marked_review = review.replace(text, marked_text)
            details_content_list = [
                summary, marked_review.replace('\n', '<br>')
            ]
            details = organize_contents(details_content_list, 'details')
            li_content_list.append(tag('li', details))

          ul = organize_contents(li_content_list, 'ul')
          enum_content_list.append(ul)

    return tuple(enum_content_list)
Example #7
0
  def _make_body_content(self, mapped_data: MappingResult) -> str:
    """html の body タグを作成

    Args:
      mapped_data (MappingResult): 対応付けされた結果

    Returns:
      body タグ
    """
    body_content_list = []
    # h1コンテンツ
    h1_content = tag('h1', mapped_data.product)
    body_content_list.append(h1_content)

    # h2コンテンツ
    review_info_content = [
        tag('h2', 'レビュー情報'),
        tag('h3', tag('a', '商品レビューページ(Amazon)', href=mapped_data.link)),
        tag('h3', 'メーカー:{}'.format(mapped_data.maker)),
        tag('h3', '評価:{}'.format(mapped_data.average_stars)),
        tag('h3', 'レビュー数:{}'.format(mapped_data.total_review)),
        tag('h3', '総文数:{}'.format(mapped_data.total_text)),
    ]
    body_content_list.extend(review_info_content)

    # heatmapコンテンツ
    heatmap_content_list = [tag('h2', '属性別での文分布')]
    attr_to_star_map = mapped_data.mapping
    heatmap_dict, anchor_dict = self._reorganize_mapped_data(attr_to_star_map)
    heatmap_table = self._create_heatmap_table(heatmap_dict, anchor_dict)
    heatmap_content_list.append(heatmap_table)
    body_content_list.extend(heatmap_content_list)

    # 属性別のレビュー列挙
    enum_content_list = self._itemize_text_by_attr_and_star(attr_to_star_map,
                                                            anchor_dict)
    body_content_list.extend(enum_content_list)

    # bodyコンテンツ
    body = organize_contents(body_content_list, 'body')
    return body
Example #8
0
  def _create_heatmap_table(
      self, heatmap_dict: HeatmapDict, anchor_dict: AnchorDict
  ) -> str:
    """属性と星評価別にレビュー文中の文数をヒートマップにして可視化したものを table タグで作成

    Args:
      heatmap_dict (HeatmapDict): 属性と星評価別にレビュー文中の文数をまとめた辞書
      anchor_dict (AnchorDict): 属性と星評価別にレビュー文の情報をまとめたリストとアンカーを格納した辞書

    Returns:
      ヒートマップを実装した table タグ
    """
    tr_content_list = [tag('th', '属性', class_='first')]
    star_strs = tuple(STAR_DISPLAY_DICT[star_str] 
                      for star_str in STAR_CORRESPONDENCE_DICT.values())
    tr_content_list.extend([tag('th', star_str) 
                            for star_str in star_strs[:-1]])
    tr_content_list.append(tag('th', star_strs[-1], class_='last'))
    tr = organize_contents(tr_content_list, 'tr')
    thead = tag('thead', tr)

    jump_fmt = '#{}'
    tbody_content_list = []
    for attr in heatmap_dict:
      if attr != "その他":
        attr_anchor = tag('a', attr, 
                          href=jump_fmt.format(self._attr_ja2en[attr]))
        td_header = tag('td', attr_anchor, class_='stats-title')
        td_content_list = [td_header]
        num_texts_and_anchor_props = zip(heatmap_dict[attr].values(),
                                         anchor_dict[attr].values())
        for num_texts, anchor_prop in num_texts_and_anchor_props:
          anchor = tag('a', num_texts, 
                       href=jump_fmt.format(anchor_prop.link_id))
          td_content = tag('td', anchor)
          td_content_list.append(td_content)
        
        tr = organize_contents(td_content_list, 'tr', class_='stats-row')
        tbody_content_list.append(tr)

    tbody = organize_contents(tbody_content_list, 'tbody')
    table = organize_contents(
        [thead, tbody], 'table', class_='heat-map', cellpadding='0',
        cellspacing='0', border='0', id='heat-map-3')
    return table
Example #9
0
  def __init__(self, normalize_mode: bool = False):
    self.normalize_mode = normalize_mode

    # スタイルシートを埋め込む
    css_file = CSS_DIR / 'review_info_style.css'
    style_content = read_script(css_file, OLD_AND_NEW)
    # <script>コンテンツの用意
    js_file = JS_DIR / 'review_info_tablesorter.js'
    script_content = read_script(js_file, OLD_AND_NEW)
    # jsonファイルに依存しない<head>コンテンツの用意
    head_content_list = [
        tag('meta', charset='UTF-8'),
        tag('link', rel='stylesheet', id="tablesorter-css",
            href=TABLESORTER_CSS, type="text/css", media="all"),
        tag('script', '', type='text/javascript', src=JQUERY_JS),
        tag('script', '', type='text/javascript', src=TABLESORTER_JS1),
        tag('script', '', type='text/javascript', src=TABLESORTER_JS2),
        tag('style', style_content),
        tag('script', script_content),
    ]
    self.head_contents = tuple(head_content_list)
Example #10
0
 def _make_head_content(self, product_name: str) -> str:
   """head コンテンツの作成"""
   title = tag('title', product_name)
   head_content_list = [*self.head_contents, title]
   head = organize_contents(head_content_list, 'head')
   return head
Example #11
0
from review_research.htmlgenerator import read_script

# 展開すると https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/css/theme.metro-dark.min.css?ver=4.9.8
TABLESORTER_CSS = ('https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/'
                  '2.31.0/css/theme.metro-dark.min.css?ver=4.9.8')
JQUERY_JS = 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js'
# 展開すると https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/js/jquery.tablesorter.min.js
TABLESORTER_JS1 = ('https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/'
                   '2.31.0/js/jquery.tablesorter.min.js')
# 展開すると 'https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/js/jquery.tablesorter.widgets.min.js'
TABLESORTER_JS2 = ('https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/'
                   '2.31.0/js/jquery.tablesorter.widgets.min.js')

OLD_AND_NEW = ('TABLE_ID', 'reviewTable')
TABLE_DESIGN = 'metro-dark'
DOC_TYPE = tag('!DOCTYPE html')  # html5の宣言

class ReviewDataConvertor(object):
  """review.json ファイルの中身を見やすいように html ファイルに変換する
  
  Attributes:
    normalize_mode (bool): レビュー文を正規化する場合は True, そうでない場合は False
  """

  def __init__(self, normalize_mode: bool = False):
    self.normalize_mode = normalize_mode

    # スタイルシートを埋め込む
    css_file = CSS_DIR / 'review_info_style.css'
    style_content = read_script(css_file, OLD_AND_NEW)
    # <script>コンテンツの用意
Example #12
0
from review_research.htmlgenerator import JS_DIR
from review_research.htmlgenerator import CSS_DIR
from review_research.nlp import normalize


ANCHOR_PROP = ['link_id', 'review_text_info_list']
AnchorProp  = namedtuple('AnchorProp', ANCHOR_PROP)

STAR_DISPLAY_DICT = {'star1': '★☆☆☆☆',
                     'star2': '★★☆☆☆',
                     'star3': '★★★☆☆',
                     'star4': '★★★★☆',
                     'star5': '★★★★★'}

JQUERY_JS = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js'
DOC_TYPE = tag('!DOCTYPE html')

AnchorDict = Dict[str, Dict[str, AnchorProp]]
HeatmapDict = Dict[str, Dict[str, int]]
Attr2StarMap = Dict[str, Dict[str, Tuple[ReviewTextInfoForMapping, ...]]]

class AttrMapConvertor(object):
  """商品レビュー内の文を属性と星評価別に対応付けされた JSON ファイルを見やすいように html ファイルに変換"""

  def __init__(self, dic_dir: str):
    self.dic_dir = dic_dir
    self.__category = ''
    self._mapper = None

    js_file = JS_DIR / 'heatmap.js'
    css_file = CSS_DIR / 'heatmap.css'