過去の日記

2017-02-10

scrapy で取得順をランダムにしたい [Python]

うーん。これがデフォルトで搭載されていないのだろうか。

まぁ、その辺の自由度どうにかならない? というissueはありましたけど。

https://github.com/scrapy/scrapy/issues/2435


完全にランダムでよければ、キューがメモリに収まっている範囲に限定ですが、こんな感じでできました。

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 [Python]

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で実行されているのかチェックしたい [Python]

理由は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 [novel]

技術書とかも読んでたから今月はこれだけ。(あと1冊進行中)
「雲南省スー族~」「くすんだ言語」は面白かった。「くすんだ言語」は技術的な描写が気になったけど、まぁ大きな問題ではない。
「ゲームの王国」長編の一部を採録するとかあり? と思ったけど読んでみたら、なるほど採録したくなるわけだ、という感じ。

伊藤計劃トリビュート2 (ハヤカワ文庫JA)

  • 作者: 草野 原々,ぼくのりりっくのぼうよみ,柴田 勝家,黒石 迩守,伏見 完,小川 哲
  • 出版社/メーカー: 早川書房
  • 発売: 2017-01-24
  • ASIN: 4150312605
  • メディア: 文庫
  • amazon.co.jp詳細へ

2017-02-28

カスタムなエンコードエラー対処 [Python]

JavaやScalaで前にやったのと同じ。

prima materia - diary : MalformedInputException


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系です。