2017-02-10
■scrapy で取得順をランダムにしたい
うーん。これがデフォルトで搭載されていないのだろうか。
まぁ、その辺の自由度どうにかならない? というissueはありましたけど。
完全にランダムでよければ、キューがメモリに収まっている範囲に限定ですが、こんな感じでできました。
import random
import collections
from scrapy.squeues import FifoMemoryQueue
class RandomizedMemoryQueue(FifoMemoryQueue):
def __init__(self):
super().__init__()
assert isinstance(self.q, collections.deque)
def pop(self):
q = self.q
if q:
q.rotate(random.randint(0, len(q) - 1))
return q.pop() if q else None
myproject/my_queue.py とかいう名前で保存します。(myproject が scrapyプロジェクト名として)
で、setting.py とか、設定に、
SCHEDULER_MEMORY_QUEUE = 'myproject.my_queue.RandomizedMemoryQueue'
を追加します。
2017-02-22
■ name 'IntProgress' is not defined
tqdmをJupyter Notebookで使おうと思ったのだけど、
name 'IntProgress' is not defined
というエラーで使えない。
ソースとかをいろいろ見てみたら ipywidgets パッケージがインストールされていないからみたい。
なんでインストールされていなかったのかはわからない*1けど、まぁ、
conda install ipywidgets
で直った。
condaでなければ
pip install ipywidgets
で。
*1 anacondaを使っていれば入るのだけど、minicondaを使っていたので入ってなかった、ということまではわかっている。
2017-02-24
■Jupyter Notebookで実行されているのかチェックしたい
理由はtqdmのimport。いろいろと試したが難しかった。
こんな風にしてみた。
try:
# noinspection PyUnresolvedReferences
if get_ipython().__class__.__name__ == 'ZMQInteractiveShell':
from tqdm import tnrange as trange
from tqdm import tqdm_notebook as tqdm
else:
raise RuntimeError
except (NameError, RuntimeError):
from tqdm import trange
from tqdm import tqdm
WebのNotebookではJavaScript利用のウィジェット、それ以外ではコンソール。
あるいは、
try:
# noinspection PyUnresolvedReferences
if get_ipython().__class__.__name__ == 'ZMQInteractiveShell':
from tqdm import tnrange as trange
from tqdm import tqdm_notebook as tqdm
else:
from tqdm import trange
from tqdm import tqdm
except (NameError, RuntimeError):
trange = range
tqdm = lambda x: x
として、ipython hoge.pyの時だけプログレスバーありにしたり。(Atom の Atom Runner みたいな、tqdm が効かない場合にオミットできる)
noinspection は PyCharm用の警告抑止。
QtConsoleは誤認識するので使わないでね。
2017-02-27
■伊藤計劃トリビュート2
技術書とかも読んでたから今月はこれだけ。(あと1冊進行中)
「雲南省スー族~」「くすんだ言語」は面白かった。「くすんだ言語」は技術的な描写が気になったけど、まぁ大きな問題ではない。
「ゲームの王国」長編の一部を採録するとかあり? と思ったけど読んでみたら、なるほど採録したくなるわけだ、という感じ。
2017-02-28
■カスタムなエンコードエラー対処
JavaやScalaで前にやったのと同じ。
Pythonはcodecsやdecode/encodeにerrors引数で都度指定できる。
# 正しくないバイトシークェンスを作る
err_bytes = 'あいう'.encode('utf-8')
err_bytes = err_bytes[:3] + err_bytes[4:]
err_bytes.decode('utf8')
# => raise UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 3: invalid start byte
# same as err_bytes.decode('utf8', errors='strict')
err_bytes.decode('utf8', errors='ignore')
# => 'あう'
err_bytes.decode('utf8', errors='replace')
# => 'あ��う'
ほかには、
with open(file_name, 'r', errors='ignore') as f:
...
とか
with codecs.open(file_name, 'w', 'cp932', errors='ignore') as f:
...
などとする。
さて、replaceを指定したときになんの文字で置き換えるかを指定したい、というのが今回のお話。
import codecs
def tohu_err_handler(er: UnicodeError):
if isinstance(er, UnicodeEncodeError):
return '□'.encode(er.encoding), er.end
else:
return '□', er.end
codecs.register_error('tohu', tohu_err_handler)
これで errors 引数に 'tohu’ が指定できる。
err_bytes.decode('utf-8', errors='tohu')
# => 'あ□□う'
コードはPython3系です。

