- Hatenaホットエントリの取得 -
はてなにはブログの投稿や取得、はてブ数の取得等のAPIが用意されています。
はてなブックマークドキュメント一覧 - Hatena Developer Center
上記を見る限り、Hatenaホットエントリを取得することは出来ないので、requestsでスクレイピングしてくる必要がありそうです。
import requests
import bs4
res = requests.get("http://b.hatena.ne.jp/hotentry")
bs_res = bs4.BeautifulSoup(res.text, "lxml")
hotentry = []
for x in bs_res.findAll("li", attrs={"class":"entry-unit"}):
a_tag = x.find("a", attrs={"class":"entry-link"})
if a_tag is not None:
hotentry.append((x.find("span").text, a_tag.attrs["title"], a_tag.attrs["href"]))
hotentry = sorted(hotentry, key=lambda x:int(x[0]), reverse=True)
for x in hotentry:
print('{} || {} \n {}'.format(x[0], x[1], x[2]))
上記コードでクローリングしてきた結果が以下のように出ます
1635 || Pythonの学び方と,読むべき本を体系化しました2018〜初心者から上級者まで - Lean Baseball
http://shinyorke.hatenablog.com/entry/python2018
627 || コンピューターで全漢字使用可に 6万字コード化 | NHKニュース
https://www3.nhk.or.jp/news/html/20171224/k10011270111000.html
567 || 日本テレビのみなさまへ、生活保護についての悪意のある番組放送はやめてください(大西連) - 個人 - Yahoo!ニュース
https://news.yahoo.co.jp/byline/ohnishiren/20171224-00079667/
534 || アニメ犯罪を追う海外ドラマ「ANIME CRIMES DIVISION」がカオスすぎて面白い「お前は地下遊戯王の危険さをわかっていない」 - Togetter
https://togetter.com/li/1183065
534 || みずほ銀行、人事評価と結びついた金融商品の押し売りの実態がNHKより流出 : 市況かぶ全力2階建
http://kabumatome.doorblog.jp/archives/65905156.html
...
常々良さそうです。
この結果を結果を使っていきたい。
- xonshのセレクタで選択したらBrowserで開く -
以下の記事で、python prompt toolkit (ptk)を利用した、シェル上で対話的選択する方法を記載しました。
vaaaaaanquish.hatenablog.com
これを利用して、xonshではてなホットエントリを取得してセレクトし、Browserで開くスクリプトとしてxonsh向けに書いてみます。
from __future__ import unicode_literals
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.interface import CommandLineInterface
from prompt_toolkit.key_binding.manager import KeyBindingManager
from prompt_toolkit.keys import Keys
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.margins import ScrollbarMargin
from prompt_toolkit.shortcuts import create_eventloop
from prompt_toolkit.filters import IsDone
from prompt_toolkit.layout.controls import TokenListControl
from prompt_toolkit.layout.containers import ConditionalContainer, ScrollOffsets, VSplit, HSplit
from prompt_toolkit.layout.screen import Char
from prompt_toolkit.layout.dimension import LayoutDimension as D
from prompt_toolkit.mouse_events import MouseEventTypes
from prompt_toolkit.token import Token
from prompt_toolkit.styles import style_from_dict
import webbrowser
import requests
import bs4
def _get_hotentry():
res = requests.get("http://b.hatena.ne.jp/hotentry")
bs_res = bs4.BeautifulSoup(res.text, "lxml")
hotentry = []
for x in bs_res.findAll("li", attrs={"class":"entry-unit"}):
a_tag = x.find("a", attrs={"class":"entry-link"})
if a_tag is not None:
hotentry.append((x.find("span").text, a_tag.attrs["title"], a_tag.attrs["href"]))
hotentry = sorted(hotentry, key=lambda x:int(x[0]), reverse=True)
hotentry = [('{} || {}'.format(x[0], x[1]), x[2]) for x in hotentry]
return hotentry
def _open_url(url):
webbrowser.open(url)
def _if_mousedown(handler):
def handle_if_mouse_down(cli, mouse_event):
if mouse_event.event_type == MouseEventTypes.MOUSE_DOWN:
return handler(cli, mouse_event)
else:
return NotImplemented
return handle_if_mouse_down
class InquirerControl(TokenListControl):
selected_option_index = 0
answered = False
choices = TokenListControl
def __init__(self, hotentrys, **kwargs):
self.choices = [x[0] for x in hotentrys]
self.urls = [x[1] for x in hotentrys]
super(InquirerControl, self).__init__(self._get_choice_tokens, **kwargs)
@property
def choice_count(self):
return len(self.choices)
def _get_choice_tokens(self, cli):
tokens = []
T = Token
def append(index, label):
selected = (index == self.selected_option_index)
@_if_mousedown
def select_item(cli, mouse_event):
self.selected_option_index = index
self.answered = True
cli.set_return_value(None)
token = T.Selected if selected else T
tokens.append((T.Selected if selected else T, ' > ' if selected else ' '))
if selected:
tokens.append((Token.SetCursorPosition, ''))
tokens.append((T.Selected if selected else T, '%-24s' % label, select_item))
tokens.append((T, '\n'))
for i, choice in enumerate(self.choices):
append(i, choice)
tokens.pop()
return tokens
def get_selection(self):
return self.choices[self.selected_option_index], self.urls[self.selected_option_index]
def _hotentry():
hotentry = _get_hotentry()
ic = InquirerControl(hotentry)
def __get_prompt_tokens(cli):
tokens = []
T = Token
tokens.append((Token.QuestionMark, '?'))
tokens.append((Token.Question, ' hotentrys '))
if ic.answered:
tokens.append((Token.Answer, ' ' + ic.get_selection()[0]))
_open_url(ic.get_selection()[1])
else:
tokens.append((Token.Instruction, ' (Use arrow keys)'))
return tokens
layout = HSplit([
Window(height=D.exact(1), content=TokenListControl(__get_prompt_tokens, align_center=False)),
ConditionalContainer(
Window( ic, width=D.exact(43), height=D(min=3), scroll_offsets=ScrollOffsets(top=1, bottom=1)),
filter=~IsDone())])
manager = KeyBindingManager.for_prompt()
@manager.registry.add_binding(Keys.ControlQ, eager=True)
@manager.registry.add_binding(Keys.ControlC, eager=True)
def _(event):
event.cli.set_return_value(None)
@manager.registry.add_binding(Keys.Down, eager=True)
def move_cursor_down(event):
ic.selected_option_index = (
(ic.selected_option_index + 1) % ic.choice_count)
@manager.registry.add_binding(Keys.Up, eager=True)
def move_cursor_up(event):
ic.selected_option_index = (
(ic.selected_option_index - 1) % ic.choice_count)
@manager.registry.add_binding(Keys.Enter, eager=True)
def set_answer(event):
ic.answered = True
event.cli.set_return_value(None)
inquirer_style = style_from_dict({
Token.QuestionMark: '#5F819D',
Token.Selected: '#FF9D00',
Token.Instruction: '',
Token.Answer: '#FF9D00 bold',
Token.Question: 'bold',
})
_app = Application(
layout=layout,
key_bindings_registry=manager.registry,
mouse_support=True,
style=inquirer_style
)
_eventloop = create_eventloop()
try:
cli = CommandLineInterface(application=_app, eventloop=_eventloop)
cli.run(reset_current_buffer=False)
finally:
_eventloop.close()
aliases["hotentry"] = _hotentry
これでxonsh上でのhotentryコマンドが作れました。
いざ実行してみます。
クールっぽい。
Browserで開くならあんまり意味ない気もしなくもないので、textだけでよしなに取ってくるマンを作って組み合わせたい所ですね。