人生苦短,我用Python。
Python真的是很好的語言,很好用,那么我們該如何入門呢?
我覺得不用特別的學習,只要你有C/C++的一些知識,學習Python將不是一件很困難的事情。
這樣一門語言,這樣一個很好地工具,應該是不需要太高的學習成本的,所以我《Python邊學邊用》這個系列的文章,我將邊用邊學,可能代碼不是那么“漂亮”,代碼不是那么“優(yōu)雅”,但是肯定實現(xiàn)了功能。
慢慢學,慢慢做,我會把這個工具用的越來越好。
文中描述方法不一定是最好的方法,只是我才疏學淺,自己只知道這么做能做出來,所以我就這么做了,歡迎交流批評。
要做什么
學校里有很多網(wǎng)站,教務處,研究生院,就業(yè)班,學術(shù)信息網(wǎng),學院官網(wǎng),實驗室官網(wǎng),等等等。。。。
每天各個網(wǎng)站上都會發(fā)幾條新聞,有些還是蠻重要的新聞,比如獎學金申請,但是呢,每天翻78個網(wǎng)站,從78個網(wǎng)站的10多個頁面中看一下當天的新聞,真是一件麻煩的事情。
大概都是這個樣子的

效果呢希望做成這個樣子:
每天定時收到一封郵件,郵件內(nèi)容從所有這些網(wǎng)站中提取的新聞中,找出最近3天的發(fā)布的新聞,排序后以一個列表的方式發(fā)送到我的郵箱,標題就是新聞內(nèi)容的超鏈接。

怎么做
基本思路是這樣
【抓取網(wǎng)頁 -> 提取篩選信息 -> 排序 -> 組織HTML -> 通過郵件發(fā)送】 + 定時運行
那么這里主要記錄一下【】中的主要過程
搭建開發(fā)環(huán)境
這里使用Python3.5,官網(wǎng)下載直接安裝就可以
IDE使用PyCharm,社區(qū)版免費。
基礎語法學習資料推薦 Python基礎教程,作為入門教程很合適??赐耆腴T之后,官方文檔是最好的教程
PIP安裝教程(Windows)
Python的優(yōu)點是有許許多多的好用的輪子,為了方便獲取這些輪子,需要安裝pip來方便的獲取。類似Linux的apt-get
Step1、官網(wǎng)下載
點擊打開鏈接https://pypi.python.org/pypi/pip#downloads
Step2、安裝PIP
下載完成之后,解壓到一個文件夾,用CMD控制臺進入解壓目錄,輸入:
python setup.py install
Step3、使用PIP安裝輪子
安裝好PIP之后,可以直接使用下面的語法來安裝輪子xxxxx
pip install xxxxx
抓取網(wǎng)頁
import urllib.request #庫載入 response=urllib.request.urlopen('http://meeting.xidian.edu.cn/') #打開鏈接 page = response.read() # 讀入網(wǎng)頁
查閱文檔,或得到如何改變UA的參數(shù),形成如下代碼:
url = reqUrl headers = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' } req = request.Request(url=url, headers=headers) response = request.urlopen(req) page = response.read()
獲取到的網(wǎng)頁HTML將存儲在page變量中,可以直接使用
print(page)
查看獲取到的HTML頁面,大概是這樣一些內(nèi)容,標準的HTML4頁面
提取篩選信息
得到的結(jié)果設置一個HTML頁面,HTML頁面的解析這里使用BeautifulSoup4來完成
安裝BeautifulSoup4
pip install BeautifulSoup4
官方文檔是最好的學習資料
首先需要分析頁面的HTML標簽結(jié)構(gòu)來確定怎么提取數(shù)據(jù),這里我使用Chrome瀏覽器的開發(fā)者工具來分析。
打開頁面,按F12打開代碼檢查工具
分析完了,使用BeautifulSoup提取
1、首先分離所有l(wèi)i標簽,使用select功能
pageSoup = BeautifulSoup(page, "html.parser") newsList = pageSoup.select('div[class="main-right-list"] > ul > li')
得到結(jié)果大概是這個樣子
2、然后針對每個li標簽,分離具體的url,標題和時間。
使用get_text獲得標題和時間,至于~||#|$|%|&||~這個是什么鬼,指示我用來split的標志,我覺得這個標志就不會和文本重復了,這個方法肯定不是很好,求不吐槽。
oneNewsText = oneNews.get_text('~||#|$|%|&||~').split('~||#|$|%|&||~')
得到的結(jié)果大概這個樣子
3、使用
find標簽功能,獲取href類別中的url片段oneNewsUrl = oneNews.find('a')['href']結(jié)果大概是這個樣子
4、使用
urljoin來合并url片段和主域名oneNewsUrl = parse.urljoin('http://gr.xidian.edu.cn/', oneNewsUrl)結(jié)果大概是這個樣子
5、將前面得到的時間利用datetime解析成標準時間格式
oneNewsText[1] = datetime.datetime.strptime(oneNewsText[1], '%Y-%m-%d')得到的結(jié)果大概是這個樣子
6、將獲得的時間,標題,URL合并到一個list中就得到了最終的信息提取結(jié)果
7、將日期與當前日期判斷,如果是最新兩天的新聞,就放入大list中準備返回,如果不是就丟棄(這里可以先判斷時間在進行其他的解析吧)
if (datetime.datetime.now().date() - oneNewsText[0].date() <=datetime.timedelta(days=NewsDataDelet)): lnewsalllist.append(oneNewsText)
然后就ok啦,所有代碼時這樣的
def gr_xidian(reqUrl,NewsDataDelet): lnewsalllist = [] url = reqUrl headers = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' } req = request.Request(url=url, headers=headers) response = request.urlopen(req) page = response.read() pageSoup = BeautifulSoup(page, "html.parser") newsList = pageSoup.select('div[class="main-right-list"] > ul > li') for oneNews in newsList: oneNewsText = oneNews.get_text('~||#|$|%|&||~').split('~||#|$|%|&||~') oneNewsUrl = oneNews.find('a')['href'] oneNewsUrl = parse.urljoin('http://gr.xidian.edu.cn/', oneNewsUrl) oneNewsText.append(oneNewsUrl) oneNewsText[1] = datetime.datetime.strptime(oneNewsText[1], '%Y-%m-%d') oneNewsText[0],oneNewsText[1] = oneNewsText[1],oneNewsText[0] del oneNewsText[2] if (datetime.datetime.now().date() - oneNewsText[0].date() <= datetime.timedelta(days=NewsDataDelet)): lnewsalllist.append(oneNewsText) return lnewsalllist
同理書寫獲取解析其他網(wǎng)站的函數(shù),最后得到的所有解析結(jié)果大概是這樣的
這里用到了BeautifulSoup,datetime和urllib的parse
說一下時間轉(zhuǎn)換吧,來自網(wǎng)絡,詳細自行Google
Ref:python BeautifulSoup 抓取網(wǎng)頁內(nèi)指定內(nèi)容
用python的BeautifulSoup分析html
排序
排序就很簡單啦,直接用的list的sort
newsAllList.sort(key=lambda x: x[0],reverse=True)
這里有一個知識點是lambda表達式x:x[0],就是x是list中的每一個元素,排序按照x[0]來進行比較,自己猜測體會的,不一定說的很完備
組織HTML
這里呢,要說一說,遇到了一些坑。
根據(jù)我邊學習邊Google的結(jié)果,最先知道的方法是Python直接填寫HTML,感覺太麻煩。
后來又找到了一個PYH,據(jù)說能比較方便的組織HTML,未研究。來自Google Code,傳送門
后來找到了Web框架,感覺找到了救星
參考知乎回答,確定了使用最簡單的Flask框架
關(guān)于虛擬環(huán)境,其實不需要,直接使用本機環(huán)境運行就可以
其他過程參考這篇教程
最后在windows的cmd中執(zhí)行下面的語句開啟Flask服務器
python run.py
在瀏覽器訪問
http://localhost:5000
獲得結(jié)果
雖然說這使用模板完成了HTML的解析,但是需要運行一個服務器,然后通過瀏覽器訪問這個服務器,和我的要求不符合。
遂研究發(fā)現(xiàn)Flask使用render_template來進行HTML渲染
page = render_template("index.html", title = 'Home', info = infomation, postList = posts)
那么render_template方法能不能用來直接渲染HTML,嘗試未果。放棄
模板從天而降
查詢發(fā)現(xiàn)Flask使用的是Jinja2引擎,所以能不能直接調(diào)用這個引擎呢,嘗試未果
又找到了Mako模板引擎
Mako是一個高性能的Python模板庫,它的語法和API借鑒了很多其他的模板庫,如Django、Jinja2等等。
需要一個HTML模板(其實什么模板都可以,使用HTML模板渲染出來的就是HTML)和一個腳本
渲染出來的結(jié)果,大概時這樣
好,下面就這個干
渲染很簡單,直接建立Mako的Template,然后使用render方法就可以進行渲染
from mako.template import Template def rederHtml(templateFile,postlist): t = Template(filename=templateFile) page = t.render( name = 'Jack', postlist = postlist ) return page
需要提前寫好模板
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>XidianNews</title> </head> <body> <div class="newslist"> <table> <tbody> % for post in postlist: <tr bgcolor="${loop.cycle('#cce0ff', '#e6f0ff')}"> <td width="95" align="center" class="arctime"><font size = "3">${post['time']}</font></td> <td class="arctitle"><a target="_blank" href=${post['url']} title="Click to open in new tab"><font size = "3">${post['body']}</font></a></td> </tr> % endfor </tbody> </table> </div> </body> </html>
Ref:PYH
Web框架比較
Flask教程
Mako語法
通過郵件發(fā)送
發(fā)郵件使用smtplib完成,可以使用import traceback來跟蹤詳細的調(diào)試信息
`def SendMail(title,mailHtml,rcvList):
sender = '15829911730@sina.cn'
pwd = 'sina2011'
smtpHost = 'smtp.sina.com'
smtpPort = '25'
message = MIMEText(mailHtml, 'html')
message['Subject'] = title
message['From'] = sender
for receiver in rcvList:
message['To'] = receiver
try:
smtpObj = smtplib.SMTP_SSL(smtpHost)
#smtpObj.set_debuglevel(1)
smtpObj.login(sender, pwd)
smtpObj.sendmail(sender, receiver, message.as_string())
print("Success to send to",receiver)
except smtplib.SMTPException as e:
errorMsg = "Error: %s" % (e)
print(errorMsg)
# traceback.print_exc()
else:
smtpObj.quit()`
通過smtplib的調(diào)試信息可以得到與服務器之間交互的信息
smtpObj.set_debuglevel(1)
得到大概這樣子的反饋信息
Ref:Python smtplib發(fā)送郵件
python3 發(fā)郵件實例(包括:文本、html、圖片、附件、SSL、群郵件)
Python3 SMTP發(fā)送郵件
好啦,到這里就結(jié)束了
以上