PythonでcPickleを使用する際に,"maximum recursion depth exceeded"というエラーが出る
久しぶりにPythonの話をする気がします.
BeautifulSoupと(c)Pickleについてです.
問題
BeautifulSoupによってHTMLから取得した文字列を,cPickle*1を用いて保存しようとしました.
import filecache # ファイルキャッシュ用のプログラム(cPickleのラッパ.他人が書いたものなので見せられない) from bs4 import BeautifulSoup # BeautifulSoupのバージョンは4 # (略) class CiteSeerXCrawler(object): # (略) def get_abstract(self, url): ''' 入力としてURLを受け取り,CiteSeerXの論文詳細ページから,アブストラクトを返す ''' abstract = '' html = self._get_html(url) # HTMLの取得 soup = BeautifulSoup(html, 'html.parser') # BeautifulSoup if soup.find('div', {'id': 'abstract'}): soup_abstract = soup.find('div', {'id': 'abstract'}).p abstract = soup_abstract.string # BeautifulSoupにより取得した文字列 (*) # (**) return abstract class GoogleScholarArticleCrawler(object): # (略) def get_abstract(self, cluster_id): ''' Cluster_idを受け取り,対応する論文のアブストラクトを返す ''' abspath = os.path.dirname(os.path.abspath(__file__)) abstract = filecache.Client(abspath + '/abstract/') cache = abstract.get(str(cluster_id)) # キャッシュから取り出す if cache is not None and cache['status'] == 'OK': return cache['data'] else: art = self.get_bibliography(cluster_id) result = {'status': '', 'data': []} # CiteSeerXによる引用論文の取得 if art["title"][0] is not None: abst = '' c = CiteSeerXCrawler() search_results = c.search_with_title(art['title'][0], num=1) time.sleep(1) if len(search_results) > 0: abst = c.get_abstract(search_results[0]) result['data'].append(abst) # 取得した文字列を追加 if len(result['data']) > 0: result['status'] = 'OK' abstract.set(str(cluster_id), result) # キャッシュに保存 else: result['status'] = 'NG' return result['data']
すると,以下のようなエラーを吐いて,中身の無いファイルを出力してしまいます.
Traceback (most recent call last): File "lib/crawler/google_scholar_abstract.py", line 15, in <module> abstract = g.get_abstract(sys.argv[1]) File "/home/lethe/LiteratureSearchEngine/lib/crawler/google_scholar_article_crawler.py", line 233, in get_abstract abstract.set(str(cluster_id), result) File "/home/lethe/LiteratureSearchEngine/lib/crawler/filecache.py", line 46, in set pickle.dump(value) File "/usr/lib/python2.7/copy_reg.py", line 74, in _reduce_ex getstate = self.__getstate__ RuntimeError: maximum recursion depth exceeded
解決策
BeautifulSoupの結果のstringを文字列と思い込んだのがまずかったらしい.
上のソースコードの(**)の部分に
print type(soup_abstract.string)
を挿入して,この変数の型を調べてみると,strではなく,
<class 'bs4.element.NavigableString'>
という,BeautifulSoup固有と思われる型が返ってきました.
つまり,strでもunicodeでもないということ.
python - pickle.dump meet RuntimeError: maximum recursion depth exceeded in cmp - Stack Overflow
ここらへんを見てる限り,BeautifulSoupのオブジェクトをそのままpickleに詰め込むのはまずいみたい.
(*)の部分を
abstract = unicode(soup_abstract.string)
にするとうまく動くらしいです.
最初,原因がBeautifulSoupにあるとわからず,必死にファイルキャッシュのコードを見直していて,半日潰しました…
悔しいので載せておきます.
*1:ざっと調べた限り,pickleについても同様の問題があるかと思われます