最近豆瓣更新了反爬政策嗤锉,連封面圖片也不允許直接訪問虫溜,越來越嚴格了合敦,以前的calibre-web-douban-api
插件不能正常獲取封面,因此只能想其他辦法來實現(xiàn)封面的獲取豌汇。
插件已更新到最新幢炸,本文是記錄插件獲取封面的技術實現(xiàn),使用參考:https://fugary.com/?p=238
源碼地址:https://github.com/fugary/calibre-web-douban-api/blob/main/src/NewDouban.py
如何實現(xiàn)
其實獲取封面只需要指定Refer=https://book.douban.com
頭信息就可以了拒贱。
calibre-web
是第三方開源服務宛徊,在不能修改其源碼的情況下,要實現(xiàn)豆瓣封面需要處理兩個問題:
- 封面的預覽
- 封面下載
封面預覽
封面預覽實際是從瀏覽器根據(jù)豆瓣的封面url
直接發(fā)起請求柜思,沒有辦法增加頭信息(Chrome
瀏覽器插件倒是可以實現(xiàn))岩调,因此只能通過本地服務代理訪問豆瓣url
。
代理地址
calibre-web
是用flask
開發(fā)赡盘,可以考慮引入flask
的藍圖對象号枕,自己添加一個路由地址,在路由中轉發(fā)請求陨享,參考代碼:
from cps.search_metadata import meta
from flask import request, Response
@meta.route("/metadata/douban_cover", methods=["GET"])
def proxy_douban_cover():
cover_url = urllib.parse.unquote(request.args.get('cover'))
res = requests.get(cover_url, headers=DEFAULT_HEADERS)
return Response(res.content, mimetype=res.headers['Content-Type'])
這樣就實現(xiàn)了葱淳,通過本地的/metadata/douban_cover?cover=https://xxxx
地址顯示封面了。
服務地址
有了本地代理服務抛姑,然后就需要在返回封面數(shù)據(jù)的時候把這個代理服務替換原始的豆瓣封面地址赞厕。
這里有點麻煩,因為flask
的request
對象是通過線程本地變量實現(xiàn)定硝,元數(shù)據(jù)服務又是通過線程池去獲取元數(shù)據(jù)皿桑,線程池中是獲取不到request
對象的,嘗試獲取將會報錯。
{RuntimeError}RuntimeError('Working outside of request context.\n\nThis typically means that you attempted to use functionality that needed\nan active HTTP request. Consult the documentation on testing for\ninformation about how to avoid this problem.')
因此只有在元數(shù)據(jù)獲取之后诲侮、往外輸出之前來修改封面地址镀虐,這里通過繼承MetaRecord
重寫魔法函數(shù)__getattribute__
來實現(xiàn)封面url
地址的替換,參考代碼:
@dataclasses.dataclass
class DoubanMetaRecord(MetaRecord):
def __getattribute__(self, item): # cover通過本地服務代理訪問
if item == 'cover' and DOUBAN_PROXY_COVER:
cover_url = super().__getattribute__(item)
if cover_url:
try:
host_url = DOUBAN_PROXY_COVER_HOST_URL
if not host_url and request.host_url:
host_url = request.host_url
if host_url and host_url not in cover_url:
self.cover = host_url + DOUBAN_PROXY_COVER_PATH + urllib.parse.quote(cover_url)
except BaseException:
pass
return super().__getattribute__(item)
這樣就實現(xiàn)了豆瓣封面預覽功能了沟绪。
如果獲取的服務器地址不正確刮便,可以手動指定DOUBAN_PROXY_COVER_HOST_URL='http://nas_ip:8083/'
封面下載
這個本地代理地址不能實現(xiàn)封面下載,因為如果在保存封面的flask
路由中再次訪問其他flask
路由會卡死绽慈,感覺是因為沒有開啟flask
的多線程處理請求的原因恨旱,在不修改calibre-web
的情況下,要實現(xiàn)封面下載坝疼,可以覆蓋calibre-web
的helper.save_cover_from_url
方法搜贤,用自己寫的方法去替換掉save_cover_from_url,在檢測到是douban
的封面地址的情況下裙士,用requests
去下載封面數(shù)據(jù)入客,代碼如下:
@staticmethod
def hack_helper_cover():
save_cover = helper.save_cover_from_url
def new_save_cover(url, book_path):
if DOUBAN_COVER_DOMAIN in url:
cover_url = url
if DOUBAN_PROXY_COVER:
component = urllib.parse.urlparse(url)
query = urllib.parse.parse_qs(component.query)
cover_url = urllib.parse.unquote(query.get('cover')[0])
res = requests.get(cover_url, headers=DEFAULT_HEADERS)
return helper.save_cover(res, book_path)
else:
return save_cover(url, book_path)
helper.save_cover_from_url = new_save_cover
這樣就實現(xiàn)了封面預覽和下載了。