前言:本文有倆個目標讀者,一是不懂編程,想了解編程“介究竟是個嘛(第四聲)”的人;二是有編程經驗,不會python,但希望學習python或者需要使用題目所示功能的人。
PS:長(luo)文(li)多(luo)圖(suo),流量黨慎入
PPS:要直接看編程部分的請直接閱讀第三章前半部分和第四章之后

_(:?」∠)_大家好,新的一天,有沒有在簡書更文學編程呀?
_(:?」∠)_有沒有更口水向往寄幾一直在默默點喜歡的作者呀?
_(:?」∠)_有沒有在寫作編程的入門之路上感到萬分沮喪,甚至開始懷疑人生呀?
_(:?」∠)_恩?你問我為什么躺著?emmmm,我想這個角度可能會有驚艷的寫作思(nao)路(dong)……

開始在簡書寫作快一個月了,看了不少知名作者分享自己的寫作經驗,可到了自己要寫的時候,卻發(fā)現(xiàn)文思如癲癇,下筆如癱瘓(真相是文思和下筆都癱瘓了),這可怎么辦呢,這豈不是離寫作的夢想更遠了?于是我決定用python把喜歡的作者的所有文章全部爬下來仔細閱讀研究,看看有沒有什么寫作的技巧(感覺我要火啦!好激動!)。
會不會很多人一看到要寫程序來研究就準備關掉頁面了?(廢話,好多人看標題就掠過了)根據分享爬取簡書數據推測
簡書大約有235w的用戶,其中關注程序員欄目的有近44w,占總用戶的18%,每11個人中就有2個人在關注編程相關信息,說明簡書中程序員對程序員感興趣的人比重不在少數,可不知道有多少人,看著欄目里的大佬們寫得天書一樣的編程經驗,望而卻步。
專家盲點(expert blind spot)就是對一個事物知道的越多,就越發(fā)不記得“不知道這個事”的情形。
作為一個嘗試過C,嘗試過Java,嘗試過MATLAB,嘗試過Html、CSS,并無一例外的全都從入門到放棄的人,我實在太懂小白們啦!我在剛學習編程的時候,一直是黑人問號臉,(⊙…⊙)介是嘛?(((;???;)))介又是嘛?_(:3」∠?)_what are you 說啥捏?!越是專業(yè)的大佬們說出來的術語,越是……聽不懂。

很久前畫的關于《繪畫.從入門到放棄》的條漫,請叫我靈魂畫手
所以在我學習python的過程中,想要用更簡單易懂的語言告訴不會編程的你編程是怎樣的。(快!毫無保留地夸我?。?/p>
1.基本概念
計算機語言是指用于人與計算機之間通訊的語言,如今通用的編程語言有兩種形式:匯編語言和高級語言,高級語言是絕大多數編程者的選擇。
這里講的編程語言都是高級語言,高級語言有很多種,Java,C,PHP,Ruby,Python…
編程語言的邏輯是基本相同的,就像不管是寫新聞,還是寫日記,還是寫小說,都是人吃飯,不會是飯吃人(靈異小說除外O__O "…)。
編程語言的語法會有各自的特點,就像中文說我今天很開心,而英文說I'm happy today(直譯“我是開心今天”)。
編程語言的功能側重點也不同,objective-c主要用于ios開發(fā),php用于web開發(fā),python主要用于寫爬蟲(我編的),就像用認真的語氣寫思想匯報,用嚴謹的語氣寫論文,用逗比的語氣寫python教程一樣(逃)。
2.明確目標

簡書的大V作者們在寫作經驗分享中不斷地強調著,不管你想寫什么,先寫起來,多嘗試多練習,漸漸就找到方向了。
不過畢竟在寫作之前也說了幾十年的大白話了,就算文筆再差只要認識字自然可以直接開始寫,可是編程語言零基礎的話是什么都不知道,就算想寫,怕也是無從下筆,可編程語言知識又看不懂(碎碎念……
來自日本已經82歲的若宮正子老奶奶成為了2017年蘋果全球開發(fā)者大會年紀最大的開發(fā)者,因為她發(fā)現(xiàn)ios平臺沒有適合老年人使用的app,所以開始自學編程,進行ios開發(fā)。
在不了解編程語言的時候,看編程語法是肥腸枯燥的(我都快枯萎了),而且很容易學完就忘,可為什么老奶奶都能夠學會呢,因為她要開發(fā)老年人用的app,有了目標,就有了動力,所以就需要明確目標,你希望通過編程做什么。
推薦python一則因為它的語法自由度高,語言簡潔清晰,適合初學者學習;二則因為…當然是因為它可以做很多肥(ke)腸(yi)有(zhuang)趣(bi)的事情啦!每次看到別人拿著什么大數據,各種圖表、分析,快告訴我你真的一點也沒有羨慕嗎?!
零基礎開發(fā)一個app可能需要幾個月,但零基礎學python到做點小爬蟲可能只需要幾天(誘不誘人?心不心動?),而在互聯(lián)網強大的開源環(huán)境下,寫出大爬蟲也是指日可待啊(快醒醒)。
好了,不廢(zuo)話(meng)了(擦口水),寫作沒題材無從下筆我?guī)筒涣四?,爬蟲的目標已經選好啦,來爬一爬簡書大V們寫的文。
3.撰寫提綱
為什么要在編程之前寫提綱?
就像寫小說一樣,分段,分章節(jié),分情節(jié),是為了搭建故事的框架,為了更好的講故事,也是為了防止自己寫著寫著就想不起來自己為什么要這么寫了(我承認我是最后一種)。
在寫提綱這件事上,編程比寫小說簡單多了,因為“代碼是凝固的文字,而小說是有張力的文字”(引自知乎無色方糖),一旦你知道自己要用編程做什么,代碼的堆砌是有跡可循的,但即使你知道小說劇集的終點是什么了,怎么寫得精彩絕倫,那就不得而知了,這樣想是不是覺得編程比寫小說容易多啦?
我以前曾經說過,爬蟲是模擬用戶上網行為的一種程序,所以我們需要思考的就是在得到作者文章合輯pdf之前,我們都做了什么?

當爬蟲工作時,它在做什么
沒有學過編程的你,看懂了哪一步?黑字?紫字?還是紅字?或者藍字?
黑字就是一個對我們要人肉完成生成作者文章為pdf這個目的時需要做的。
紫字是從機器角度去思考爬蟲需要做的。
紅字是編程中的函數,每一個功能都是有一個一個函數運行完成的。
藍字是從外部引入的功能模塊。
是不是已經蒙圈了?
我們換個角度來解釋。
本米打算寫一部驚世駭俗的史詩級小說,“擁有絕世美顏的女主因不堪繼母的百般刁難發(fā)奮圖強一舉考入清華大學飛禽系脫離家庭并靠自己不畏艱苦的精神一邊兼職神奇動物飼養(yǎng)員一邊讀書最終以優(yōu)異的成績進入動物城青眼白龍村母龍聯(lián)合會工作并在那里好巧不巧地因為養(yǎng)殖經驗豐富受到了有著童年陰影的魔法界公眾人物也就是男主角的崇拜男主盛情邀請女主參觀他的妙蛙種子試驗田的時候附近地面遭到了外星飛船的撞擊女主被外星人附身失去原本記憶男主遠走他鄉(xiāng)為其尋找解救之法卻不小心穿越至石器時代又在瘋狂原始人的幫助下被神仙發(fā)現(xiàn)神仙了解男女主的故事后大為感動仙杖一揮趕走了外星人并許了他們三生三世的兄妹情緣”……

聽到神奇動物、青眼白龍、妙蛙種子這些詞的時候,有沒有覺得很熟悉,有沒有直接腦補出一段記憶深處早已存在的劇情?這就是類似于編程中外部引入的功能模塊,這個模塊早已存在了,它也并非我寫的,剛好它擁有我需要的功能,所以我就將它引入到我正在編寫的代碼中,這樣它本身包含的功能我就可以直接使用了。
仔細分解故事,大致可分為女主家庭篇、女主大學篇、女主工作篇、男主篇、男主女主相識篇、外星事故篇、千里解救女主篇、大團圓篇,這里的人物角色,代表著程序中的參數;每一個故事的章節(jié),就代表著一個的函數。不同的函數代表著不同的功能,函數與函數之間相互聯(lián)系,完成程序的任務(類似于展示故事的情節(jié)),傳遞共同的參數(可以理解為角色貫穿整個故事)。
程序語言中還有一些內置函數,內置函數是程序本身自己就有的函數,就像中文寫吃東西用吃飯,英文用eat,日文用食べる。
通過對內置函數的使用,模塊的調用,以及函數功能的搭建,就組成了一個完整的程序。
4.構建代碼
本段開始建議有編程基礎再閱讀,當然你沒編程基礎也看得懂那我也敬自己的口才是條漢子。

4.1 偽裝瀏覽器打開頁面
defgetPage(url):#獲取鏈接中的網頁內容 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36' } try: request = urllib2.Request(url = url, headers = headers) response = urllib2.urlopen(request, timeout = 5) page = response.read().decode('utf-8') return page except (urllib2.URLError,Exception), e: if hasattr(e, 'reason'): print'抓取失敗,具體原因:', e.reason response = urllib2.urlopen(request,timeout = 5) page = response.read().decode('utf-8') return pageuser-agent可以理解為爬蟲的瀏覽器馬甲,披上了這個瀏覽器馬甲,爬蟲就會像我們平常上網時打開瀏覽器輸入網址就可以看到網頁一樣得到需要的網頁內容,這是為了應對低階的反爬蟲技術所采取的措施,關于爬蟲和反爬蟲的戰(zhàn)爭,改天再嘮。

4.2 分析個人主頁
抓一個簡書作者,懷左同學的網址是這樣的“http://www.jianshu.com/u/62478ec15b74”,多觀察幾個個人頁地址就會發(fā)現(xiàn)只有“http://www.jianshu.com/u/”后面的那一串字母和數字組成的字符串會有變化。
簡書個人主頁內包含了作者的信息,文章總數,也包括了文章的標題,往下拉頁面,會發(fā)現(xiàn)文章不斷的加載出來,應該一直往下翻可以翻到第一篇文章,但如果右鍵查看源代碼,就只能看到已經加載出來的文章源碼。
文章是動態(tài)加載的,需要在chrome瀏覽器右鍵檢查,在彈出窗口中選擇network,這時繼續(xù)下拉頁面,觀察左下角的列表變化,里面有一個包含page字樣的鏈接文件,不一定在xhr分類下,不過一般就那幾個分類里。

加載出的頁面是從page=2開始的,試著打開http://www.jianshu.com/u/62478ec15b74?order_by=shared_at&page=1,發(fā)現(xiàn)可以獲得與http://www.jianshu.com/u/62478ec15b74內容一樣的頁面,從而得到爬取所有文章列表的網頁url。
4.3 獲取作者信息、文章鏈接
節(jié)選個人頁源代碼
<pclass="title"><aclass="name"href="/u/62478ec15b74">懷左同學</a><spanclass="author-tag"><iclass="iconfont ic-write"></i> 簽約作者</span></p>作者的姓名在title.name下,正則表達式為:
pattern = re.compile(u'<a.*?class="name".*?href=".*?">(.*?)</a>')節(jié)選個人頁源代碼
<pclass="info"><ul><li><pclass="meta-block"><ahref="/users/62478ec15b74/following"><p>17</p> 關注 <iclass="iconfont ic-arrow"></i></a></p></li><li><pclass="meta-block"><ahref="/users/62478ec15b74/followers"><p>63600</p> 粉絲 <iclass="iconfont ic-arrow"></i></a></p></li><li><pclass="meta-block"><ahref="/u/62478ec15b74"><p>244</p> 文章 <iclass="iconfont ic-arrow"></i></a></p></li>文章數隱藏在info.meta-block下,但meta-block下會匹配到的值不止一個,用于區(qū)別值的幾個href都是根據作者生成,不適用于所有作者,所以選擇將匹配的值保存在list中,查看源碼可推出需要的值在list中第三個,于是返回list[2]的值。
pattern = re.compile(u'<p>(.*?)</p>')metablock = pattern.findall(page)titleNum = int(metablock[2])節(jié)選個人頁源代碼
<a class="title"target="_blank"href="/p/c2a4a3b3490e">通過自律,我擁有了一個高配的暑假</a>這里匹配的是文章的標題,可以看出前面的href中的值"/p/c2a4a3b3490e"對應著文章鏈接的尾部,一并保存并轉為網址形式,將匹配到的值存入1個list中(下面的代碼還匹配了發(fā)表文章的時間)
pattern = re.compile(u'<span.*?class="time".*?data-shared-at="(.*?)+08:00"></span>.*?' + u'<a.*?class="title".*?href="(.*?)">(.*?)</a>',re.S)titles = re.findall(pattern,page) for title in titles: titlelist.append([title[0],'http://www.jianshu.com' + title[1],title[2]]) print'正在讀取第' + str(num) + '篇文章鏈接' num +=14.4 將網頁轉為pdf
咦,這么快就要轉pdf了嗎?這不才剛讀取了文章鏈接嗎?這不還沒讀取文章內容呢嘛?
hiahiahiahia~這就要介紹一個引入的模塊,一個神器!wkhtmltopdf是一個可以直接將網頁轉化為pdf的模塊,也可以通過相應的函數設置網頁指定部分轉化為pdf。
當然我們還是要讀取文章內容噠,但不需要單獨設置函數讀取文章了,在轉為pdf的函數中直接讀取,此處參考了Python 爬蟲:把廖雪峰教程轉換成 PDF 電子書。
https://foofish.net/python-crawler-html2pdf.html

依舊在chrome中打開簡書文章右鍵“檢查”,從圖片中可以看出,title對應著標題,show-content對應著正文,代碼如下,articlelist中存放著上一節(jié)讀取的讀者文章信息,這里使用的是Beautifulsoup匹配的源碼信息。
for index,url inenumerate(articlelist): try: response = requests.get(url[1]) soup = BeautifulSoup(response.content,"html.parser") title = soup.find('h1').get_text() #寫入標題 body = soup.find_all(class_="show-content")[0] #寫入正文#標題加入到正文的最前面,居中顯示 center_tag = soup.new_tag("center") title_tag = soup.new_tag('h1') title_tag.string = title center_tag.insert(1, title_tag) body.insert(1, center_tag) html = str(body) pattern = "(<img.*?src=")(//upload.*?)(")"def func(m): if not m.group(2).startswith("http"):#檢查是否以http開頭 rtn = "".join([m.group(1), "http:", m.group(2), m.group(3)]) return rtn else: return"".join([m.group(1), m.group(2), m.group(3)]) html = re.compile(pattern).sub(func, html) #將圖片相對路徑轉為絕對 html = html_template.format(content=html) html = html.encode("utf-8") f_name = ".".join([str(index),"html"]) with open(f_name, 'wb') as f: f.write(html) htmls.append(f_name) except Exception as e: print etry: pdfkit.from_file(htmls, authorname + "的文章合輯.pdf", options=options)#將html文件合并為pdfexcept Exception as e: print efor html in htmls: os.remove(html) #刪除緩存的html文件

pdf效果(mac)
Mac字有點小QAQ,看下windows的。

pdf效果(windows)
(*^__^*)
4.5 獲取詞云
在寫程序的過程中,又增加了一個想法,在python中使用詞云分析簡書作者文章的關鍵詞,于是又多寫了幾行。沒有甲方的程序,想加什么功能就加什么功能(比剪刀手)。
思路是根據在4.3節(jié)中提取的文章鏈接,讀取文章中文本內容,輸出到txt文件中,再使用python的第三方模塊jieba(這個模塊中文翻譯是結巴?結巴!結巴……哈哈哈哈哈哈嗝),通過這個模塊,就可以將大段的文本按照詞匯分開,而且支持中文分詞!不要問我這個分詞有啥用,計算機不是學過中文的,在它看來中文都是@!#¥%…&*。
filePath = './純文章.txt'fileArticle = open(filePath, 'w')try: for article in articlelist: fileArticle.write(article[3])finally: fileArticle.close()text = open(filePath).read()os.remove(filePath)#使用jieba整理文本wordlist = jieba.cut(text,cut_all = False)wl = "/ ".join(wordlist)f_stop = open(stopwords_path)try: f_stop_text = f_stop.read() f_stop_text=unicode(f_stop_text,'utf-8')finally: f_stop.close()f_stop_seg_list = f_stop_text.split('n')for myword in wl.split('/'): ifnot(myword.strip() in f_stop_seg_list) andlen(myword.strip())>1: mywordlist.append(myword)text = ''.join(mywordlist)得到經過分詞后的文件,使用python的第三方模塊wordcloud輸出詞云,wordcloud模塊可以引入自定義圖片,并根據圖片的輪廓生成詞云,同時支持引入字體。
wc.generate(text)# 生成詞云, 用generate輸入全部文本,也可以我們計算好詞頻后使用generate_from_frequencies函數image_colors = ImageColorGenerator(back_coloring) # 從背景圖片生成顏色值plt.figure() #繪制圖片wc.to_file(imgname1) # 保存圖片plt.figure()plt.imshow(wc.recolor(color_func=image_colors))wc.to_file(imgname2) # 保存圖片我曾想過以作者頭像為背景圖生成詞云,但發(fā)現(xiàn)有些作者的頭像生成詞云的效果并不好,于是我選擇了固定圖片作為詞云背景,生成了懷左同學的詞云。

懷左同學文章詞云
懷左同學果然是學霸呀(●─●),努力、生活、寫作、讀書、學習……
好!我也決定要努力學習編程,努力工作(flag*MAX),不說了!我去努力了?。ㄌ?/p>
我又回來了,gayhub源文件已上傳,隨意下載
代碼均設置了時間間隔,雖然只是很小的爬蟲,但是也不要給簡書叔叔增加服務器壓力啦~對啦,代碼是基于Python2.7噠~
關于python基礎入門的學習資料,我推薦這本書,Python 2.7教程,里面也有python3的教程。
https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000
如果有什么關于代碼的疑問歡迎質詢,我會本著科♂學的態(tài)度認真回復的:在我的電腦上跑是好的。(再逃
4.6 揭開json的面紗
我會讀取json文件啦。
情況是這樣的,之前程序的設定是輸入所需要作者的個人主頁鏈接,但我希望程序是只需要輸入作者的名字就可以運行。
于是我分析出搜索頁的網址:"http://www.jianshu.com/search?q=懷左同學&page=1&type=user",查看源代碼,發(fā)現(xiàn)源代碼中沒有搜索結果的顯示(和說好的不一樣?。∵@不科學?。?。
查了很多資料,大概知道這是網頁的異步加載,于是又要動用chrome的另一個神器,檢查-network了。

與4.2節(jié)相同,在搜索結果頁中刷新頁面,發(fā)現(xiàn)在xhr分類下多了倆個文件,點擊第一個文件,查看右下角的preview,列表里不正是我們需要的搜索結果嗎?那么怎么把它提取出來呢?
一般情況下我是查看preview旁邊的headers選項卡中的requests URL:http://www.jianshu.com/search/do?q=%E6%80%80%E5%B7%A6%E5%90%8C%E5%AD%A6&type=user&page=1&order_by=default,但點擊這個URL之后發(fā)現(xiàn)沒有任何內容。
一開始我以為我努力的方向錯了,在散發(fā)著大神之光的程序員小哥哥前輩的指點下,我下載了一個chrome插件:postman,將剛剛的網址粘貼到postman的瀏覽器中,發(fā)現(xiàn)打開之后就是我需要的內容!

經過一番努力,知道了用這個鏈接直接在瀏覽器請求無法得到正確的網頁內容是因為沒有帶正確的headers。

依然在chrome的檢查中查看這個headers中的request header,將這些內容全部貼到代碼的請求頭中,全部代碼如下。
defgetUrl(): userlink = [] while len(userlink) == 0: authorname = raw_input('請輸入想查詢的作者的名稱:') url = "http://www.jianshu.com/search/do?q=" + authorname +"&type=user&page=1&order_by=default" headers = { 'User-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0', 'Host' : 'www.jianshu.com', 'Accept' : 'application/json', 'Accept-Language' : 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding' : 'gzip, deflate', 'Referer' : 'http://www.jianshu.com/search?q=' + authorname +'&page=1&type=user', 'Cookie' : '出現(xiàn)的cookies信息', 'DNT' : '1', 'Connection' : 'keep-alive', 'If-None-Match' : 'W/"89003709c764d0a3ece1d180f5d1c7df"', 'Cache-Control' :'max-age=0' } json_data = requests.get(url = url ,headers = headers).json() #獲取網頁中的json文件。for i in json_data['entries']: nickname = i['nickname'] slug = i['slug'] if nickname == authorname: return slug breakelse: print'輸入的作者名稱不符合規(guī)范,請重新輸入。'這里需要了解關于python中json和淺拷貝與深拷貝的知識點,可以看到(如果你看不到請上翻頁面到postman那里再看一遍圖),我們需要匹配的內容在entries的nickname下,而需要得到的內容是與nickname同一組的slug值,slug值其實就是作者個人主頁/u/后面的唯一標識碼,遍歷即可匹配啦~