右鍵+清除本來好好的按一個N就可以,現在整的啥?清除個內容還要按3個鍵?
1186
2022-05-29
大家好,我是四毛。
今天主要講一下如何將某一個知乎問題的所有答案轉換為本地MarkDown文件。
前期準備
python2.7
html2text
markdownpad(這里隨意,只要可以支持md就行)
會抓包。。。。。
最重要的是你要有代理,因為知乎開始封IP了
1.什么是MarkDown文件
Markdown 是一種用來寫作的輕量級「標記語言」,它用簡潔的語法代替排版,而不像一般我們用的字處理軟件?Word或?Pages?有大量的排版、字體設置。它使我們專心于碼字,用「標記」語法,來代替常見的排版格式。例如此文從內容到格式,甚至插圖,鍵盤就可以通通搞定了。
恩,上面是我抄的,哈哈。想多了解的可以看看這里。
2.為什么要將答案轉為MarkDwon
因為。。。。。。懶,哈哈,開個玩笑。最重要的原因還是markdown看著比較舒服。平時寫腳本的時候,也一直在思考一個問題,如何將一個文字與圖片穿插的網頁原始的保存下來呢。如果借助工具的話,那就很多了,CTRL+P ?打印的時候,選擇另存為PDF,或者搞個印象筆記,直接保存整個網頁。那么,我們如何用爬蟲實現呢?正好前幾天看到了這個項目,仔細研究了一下,大受啟發。
3.原理
原理說起來很簡單:獲取請求到的內容的BODY部分,然后重新構建一個HTML文件,接著利用html2text這個模塊將其轉換為markdown文件,最后對圖片及標題按照markdown的格式做一些處理就好了。目前應用的場景主要是在知乎。
4.Show Code
4.1獲取知乎答案
寫代碼的時候,主要考慮了兩種使用場景。第一,獲取某一特定答案的數據然后進行轉換;第二,獲取某一個問題的所有答案進行然后挨個進行轉換,在這里可以 通過贊同數來對要獲取的答案進行質量控制。
4.1.1、某一個特定答案的數據獲取
url:https://www.zhihu.com/question/27621722/answer/48658220(前面那個是問題ID,后邊的是答案ID)
這一數據的獲取我這里分為了兩個部分,第一部分請求上述網址,拿到答案主體數據以及贊同數,第二部分請求下面這個接口:
https://www.zhihu.com/api/v4/answers/48658220
為什么會這樣?因為這個接口得到的答案正文數據不是完整數據,所以只能分兩步了。
4.1.2、某一個特定答案的數據獲取
這一個數據就可以通過很簡單的方式得到了,接口如下:
https://www.zhihu.com/api/v4/questions/27621722/answers?sort_by=default&include=data%5B%2A%5D.is_normal%2Cis_collapsed%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Cmark_infos%2Ccreated_time%2Cupdated_time%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B%2A%5D.author.follower_count%2Cbadge%5B%3F%28type%3Dbest_answerer%29%5D.topics&limit=20&offset=3
返回的都是JSON數據,很方便獲取。但是這里有一個地方需要注意,從這里面取的答案正文數據就是文本數據,不是一個完整的html文件,所以需要在構造一下。
4.1.2、保存的字段
author_name 回答用戶名
answer_id ?答案ID
question_id 問題ID
question_title ?問題
vote_up_count ?贊同數
create_time ?創建時間
答案主體
4.2 Code
主腳本:zhihu.py
#!/usr/bin/env?python #?-*-?coding:?utf-8?-*- #?Created?by?shimeng?on?17-6-5 import?os import?re import?json import?requests import?html2text from?parse_content?import?parse ? """ just?for?study?and?fun Talk?is?cheap show?me?your?code """ ? class?ZhiHu(object): ????def?__init__(self): ?????????self.request_content?=?None ? ????def?request(self,?url,?retry_times=10): ????????header?=?{ ????????????'User-Agent':?'Mozilla/5.0?(X11;?Linux?x86_64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/57.0.2987.133?Safari/537.36', ????????????'authorization':?'oauth?c3cef7c66a1843f8b3a9e6a1e3160e20', ????????????'Host':?'www.zhihu.com' ????????} ????????times?=?0 ????????while?retry_times>0: ????????????times?+=?1 ????????????print?'request?%s,?times:?%d'?%(url,?times) ????????????try: ????????????????ip?=?'your?proxy?ip' ????????????????if?ip: ????????????????????proxy?=?{ ????????????????????????'http':?'http://%s'?%?ip, ????????????????????????'https':?'http://%s'?%?ip ????????????????????} ????????????????????self.request_content?=?requests.get(url,?headers=header,?proxies=proxy,?timeout=10).content ????????????except?Exception,?e: ????????????????print?e ????????????????retry_times?-=?1 ????????????else: ????????????????return?self.request_content ? ????def?get_all_answer_content(self,?question_id,?flag=2): ????????first_url_format?=?'https://www.zhihu.com/api/v4/questions/{}/answers?sort_by=default&include=data%5B%2A%5D.is_normal%2Cis_collapsed%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Cmark_infos%2Ccreated_time%2Cupdated_time%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B%2A%5D.author.follower_count%2Cbadge%5B%3F%28type%3Dbest_answerer%29%5D.topics&limit=20&offset=3' ????????first_url?=?first_url_format.format(question_id) ????????response?=?self.request(first_url) ????????if?response: ????????????contents?=?json.loads(response) ????????????print?contents.get('paging').get('is_end') ????????????while?not?contents.get('paging').get('is_end'): ????????????????for?content?in?contents.get('data'): ????????????????????self.parse_content(content,?flag) ????????????????next_page_url?=?contents.get('paging').get('next').replace('http',?'https') ????????????????contents?=?json.loads(self.request(next_page_url)) ????????else: ????????????raise?ValueError('request?failed,?quit......') ? ????def?get_single_answer_content(self,?answer_url,?flag=1): ????????all_content?=?{} ????????question_id,?answer_id?=?re.findall('https://www.zhihu.com/question/(\d+)/answer/(\d+)',?answer_url)[0] ? ????????html_content?=?self.request(answer_url) ????????if?html_content: ????????????all_content['main_content']?=?html_content ????????else: ????????????raise??ValueError('request?failed,?quit......') ? ????????ajax_answer_url?=?'https://www.zhihu.com/api/v4/answers/{}'.format(answer_id) ????????ajax_content?=?self.request(ajax_answer_url) ????????if?ajax_content: ????????????all_content['ajax_content']?=?json.loads(ajax_content) ????????else: ????????????raise??ValueError('request?failed,?quit......') ? ????????self.parse_content(all_content,?flag,?) ? ????def?parse_content(self,?content,?flag=None): ????????data?=?parse(content,?flag) ????????self.transform_to_markdown(data) ? ????def?transform_to_markdown(self,?data): ????????content?=?data['content'] ????????author_name?=?data['author_name'] ????????answer_id?=?data['answer_id'] ????????question_id?=?data['question_id'] ????????question_title?=?data['question_title'] ????????vote_up_count?=?data['vote_up_count'] ????????create_time?=?data['create_time'] ? ????????file_name?=?u'%s--%s的回答[%d].md'?%?(question_title,?author_name,answer_id) ????????folder_name?=?u'%s'?%?(question_title) ? ????????if?not?os.path.exists(os.path.join(os.getcwd(),folder_name)): ????????????os.mkdir(folder_name) ????????os.chdir(folder_name) ? ????????f?=?open(file_name,?"wt") ????????f.write("-"?*?40?+?"\n") ????????origin_url?=?'https://www.zhihu.com/question/{}/answer/{}'.format(question_id,?answer_id) ????????f.write("##?本答案原始鏈接:?"?+?origin_url?+?"\n") ????????f.write("###?question_title:?"?+?question_title.encode('utf-8')?+?"\n") ????????f.write("###?Author_Name:?"?+?author_name.encode('utf-8')?+?"\n") ????????f.write("###?Answer_ID:?%d"?%?answer_id?+?"\n") ????????f.write("###?Question_ID?%d:?"?%?question_id?+?"\n") ????????f.write("###?VoteCount:?%s"?%?vote_up_count?+?"\n") ????????f.write("###?Create_Time:?"?+?create_time?+?"\n") ????????f.write("-"?*?40?+?"\n") ? ????????text?=?html2text.html2text(content.decode('utf-8')).encode("utf-8") ????????#?標題 ????????r?=?re.findall(r'\*\*(.*?)\*\*',?text,?re.S) ????????for?i?in?r: ????????????if?i?!=?"?": ????????????????text?=?text.replace(i,?i.strip()) ? ????????r?=?re.findall(r'_(.*)_',?text) ????????for?i?in?r: ????????????if?i?!=?"?": ????????????????text?=?text.replace(i,?i.strip()) ????????text?=?text.replace('_?_',?'') ? ????????#?圖片 ????????r?=?re.findall(r'!\((?:.*?)\)',?text) ????????for?i?in?r: ????????????text?=?text.replace(i,?i?+?"\n\n") ? ????????f.write(text) ? ????????f.close() ? ? if?__name__?==?'__main__': ????zhihu?=?ZhiHu() ????url?=?'https://www.zhihu.com/question/27621722/answer/105331078' ????zhihu.get_single_answer_content(url) ? ????#?question_id?=?'27621722' ????#?zhihu.get_all_answer_content(question_id)
zhihu.py為主腳本,內容很簡單,發起請求,調用解析函數進行解析,最后再進行保存。
解析函數腳本:parse_content.py
#!/usr/bin/env?python #?-*-?coding:?utf-8?-*- #?Created?by?shimeng?on?17-6-5 import?time from?bs4?import?BeautifulSoup ? ? def?html_template(data): ????#?api?content ????html?=?''' ???????? ????????
???????? ????????%s ???????? ???????? ???????? ????????'''?%?data ????return?html ? ? def?parse(content,?flag=None): ????data?=?{} ????if?flag?==?1: ????????#?single ????????main_content?=?content.get('main_content') ????????ajax_content?=?content.get('ajax_content') ? ????????soup?=?BeautifulSoup(main_content.decode("utf-8"),?"lxml") ????????answer?=?soup.find("span",?class_="RichText?CopyrightRichText-richText") ? ????????author_name?=?ajax_content.get('author').get('name') ????????answer_id?=?ajax_content.get('id') ????????question_id?=?ajax_content.get('question').get('id') ????????question_title?=?ajax_content.get('question').get('title') ????????vote_up_count?=?soup.find("meta",?itemprop="upvoteCount")["content"] ????????create_time?=?time.strftime("%Y-%m-%d?%H:%M:%S",?time.localtime(ajax_content.get('created_time'))) ? ? ????else: ????????#?all ????????answer_content?=?content.get('content') ? ????????author_name?=?content.get('author').get('name') ????????answer_id?=?content.get('id') ????????question_id?=?content.get('question').get('id') ????????question_title?=?content.get('question').get('title') ????????vote_up_count?=?content.get('voteup_count') ????????create_time?=?time.strftime("%Y-%m-%d?%H:%M:%S",?time.localtime(content.get('created_time'))) ? ????????content?=?html_template(answer_content) ????????soup?=?BeautifulSoup(content,?'lxml') ????????answer?=?soup.find("body") ? ????print?author_name,answer_id,question_id,question_title,vote_up_count,create_time ????#?這里非原創,看了別人的代碼,修改了一下 ????soup.body.extract() ????soup.head.insert_after(soup.new_tag("body",?**{'class':?'zhi'})) ? ????soup.body.append(answer) ? ????img_list?=?soup.find_all("img",?class_="content_image?lazy") ????for?img?in?img_list: ????????img["src"]?=?img["data-actualsrc"] ????img_list?=?soup.find_all("img",?class_="origin_image?zh-lightbox-thumb?lazy") ????for?img?in?img_list: ????????img["src"]?=?img["data-actualsrc"] ????noscript_list?=?soup.find_all("noscript") ????for?noscript?in?noscript_list: ????????noscript.extract() ? ????data['content']?=?soup ????data['author_name']?=?author_name ????data['answer_id']?=?answer_id ????data['question_id']?=?question_id ????data['question_title']?=?question_title ????data['vote_up_count']?=?vote_up_count ????data['create_time']?=?create_time ? ????return?dataparse_content.py主要負責構造新的html,然后對其進行解析,獲取數據。
5.測試結果展示
恩,下面還有,就不截圖了。
6.缺點與不足
下面聊一聊這種方法的缺點:
這種方法的最大缺點就是:
一定要聯網!
一定要聯網!
一定要聯網!
因為。。。。。。 在md文件中我們只是寫了個圖片的網址,這就意味著markdown的編輯器幫我們去存放圖片的服務器上對這個圖片進行了獲取,所以斷網也就意味著你看不到圖片了;同時也意味著如果用戶刪除了這張圖片,你也就看不到了。
但是,后來我又發現在markdownpad中將文件導出為html時,即使是斷網了,依然可以看到全部的內容,包括圖片,所以如果你真的喜歡某一個答案,保存到印象筆記肯定是不錯的選擇,PDF直接保存也不錯,如果是使用了這個方法,記得轉為html最好。
還有一個缺點就是html2text轉換過后的效果其實并不是特別好,還是需要后期在進行處理的。
7.總結
代碼還有很多可以改進之處,歡迎大家與我交流:QQ:549411552 (注明來自靜覓)
國際慣例:代碼在這
收工。
爬蟲 python
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。