Python边学边用 - 学校新闻爬取并通过邮件发送

人生苦短,我用Python。
Python真的是很好的语言,很好用,那么我们该如何入门呢?
我觉得不用特别的学习,只要你有C/C++的一些知识,学习Python将不是一件很困难的事情。
这样一门语言,这样一个很好地工具,应该是不需要太高的学习成本的,所以我《Python边学边用》这个系列的文章,我将边用边学,可能代码不是那么“漂亮”,代码不是那么“优雅”,但是肯定实现了功能。
慢慢学,慢慢做,我会把这个工具用的越来越好。
文中描述方法不一定是最好的方法,只是我才疏学浅,自己只知道这么做能做出来,所以我就这么做了,欢迎交流批评。


要做什么

学校里有很多网站,教务处,研究生院,就业班,学术信息网,学院官网,实验室官网,等等等。。。。

每天各个网站上都会发几条新闻,有些还是蛮重要的新闻,比如奖学金申请,但是呢,每天翻7~8个网站,从7~8个网站的10多个页面中看一下当天的新闻,真是一件麻烦的事情。

大概都是这个样子的


效果呢希望做成这个样子:

每天定时收到一封邮件,邮件内容从所有这些网站中提取的新闻中,找出最近3天的发布的新闻,排序后以一个列表的方式发送到我的邮箱,标题就是新闻内容的超链接。



怎么做

基本思路是这样

【抓取网页 -> 提取筛选信息 -> 排序 -> 组织HTML -> 通过邮件发送】 + 定时运行

那么这里主要记录一下【】中的主要过程

搭建开发环境

这里使用Python3.5,官网下载直接安装就可以

IDE使用PyCharm,社区版免费。

基础语法学习资料推荐 Python基础教程,作为入门教程很合适。看完入门之后,官方文档是最好的教程

PIP安装教程(Windows)

Python的优点是有许许多多的好用的轮子,为了方便获取这些轮子,需要安装pip来方便的获取。类似Linux的apt-get

Step1、官网下载

点击打开链接https://pypi.python.org/pypi/pip#downloads


Step2、安装PIP

下载完成之后,解压到一个文件夹,用CMD控制台进入解压目录,输入:

python setup.py install


Step3、使用PIP安装轮子

安装好PIP之后,可以直接使用下面的语法来安装轮子xxxxx

pip install xxxxx


Ref:windows下面安装Python和pip终极教程


抓取网页

这里没有使用爬虫框架,主要是因为做这个是为了学习Python,实现简单功能即可。

在Python2版本中,有urllib和urlib2两个库可以用来实现request的发送。而在Python3中,已经不存在urllib2这个库了,统一为urllib。

Python3 urllib库官方链接

urllib中包括了四个模块,包括urllib.request,urllib.error,urllib.parse,urllib.robotparser

  • urllib.request可以用来发送request和获取request的结果
  • urllib.error包含了urllib.request产生的异常
  • urllib.parse用来解析和处理URL
  • urllib.robotparse用来解析页面的robots.txt文件
可见其中模拟请求使用的最主要的库便是urllib.request,异常处理用urllib.error库。

基本网页获取

import urllib.request #库载入
response=urllib.request.urlopen('http://meeting.xidian.edu.cn/') #打开链接
page = response.read() # 读入网页


查阅文档,或得到如何改变UA的参数,形成如下代码:

    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()

获取到的网页HTML将存储在page变量中,可以直接使用

print(page)
查看获取到的HTML页面,大概是这样一些内容,标准的HTML4页面


Ref:使用 Python 轻松抓取网页


提取筛选信息

得到的结果设置一个HTML页面,HTML页面的解析这里使用BeautifulSoup4来完成

安装BeautifulSoup4
pip install BeautifulSoup4
官方文档是最好的学习资料



首先需要分析页面的HTML标签结构来确定怎么提取数据,这里我使用Chrome浏览器的开发者工具来分析。
打开页面,按F12打开代码检查工具


分析完了,使用BeautifulSoup提取

1、首先分离所有li标签,使用select功能
    pageSoup = BeautifulSoup(page, "html.parser")
    newsList = pageSoup.select('div[class="main-right-list"] > ul > li')

得到结果大概是这个样子



2、然后针对每个li标签,分离具体的url,标题和时间。
使用get_text获得标题和时间,至于“~||#|$|%|&||~”这个是什么鬼,指示我用来split的标志,我觉得这个标志就不会和文本重复了,这个方法肯定不是很好,求不吐槽。
oneNewsText = oneNews.get_text('~||#|$|%|&||~').split('~||#|$|%|&||~')
得到的结果大概这个样子



3、使用find标签功能,获取href类别中的url片段
oneNewsUrl = oneNews.find('a')['href']
结果大概是这个样子


4、使用urljoin来合并url片段和主域名
oneNewsUrl = parse.urljoin('http://gr.xidian.edu.cn/', oneNewsUrl)
结果大概是这个样子


5、将前面得到的时间利用datetime解析成标准时间格式
oneNewsText[1] = datetime.datetime.strptime(oneNewsText[1], '%Y-%m-%d')
得到的结果大概是这个样子


6、将获得的时间,标题,URL合并到一个list中就得到了最终的信息提取结果


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

同理书写获取解析其他网站的函数,最后得到的所有解析结果大概是这样的




 这里用到了BeautifulSoup,datetime和urllib的parse
说一下时间转换吧,来自网络,详细自行Google




排序

排序就很简单啦,直接用的list的sort
newsAllList.sort(key=lambda x: x[0],reverse=True)
这里有一个知识点是lambda表达式x:x[0],就是x是list中的每一个元素,排序按照x[0]来进行比较,自己猜测体会的,不一定说的很完备



组织HTML

这里呢,要说一说,遇到了一些坑。
根据我边学习边Google的结果,最先知道的方法是Python直接填写HTML,感觉太麻烦。
后来又找到了一个 PYH,据说能比较方便的组织HTML,未研究。来自Google Code, 传送门
后来找到了Web框架,感觉找到了救星
参考 知乎回答,确定了使用最简单的Flask框架
关于虚拟环境,其实不需要,直接使用本机环境运行就可以
其他过程参考 这篇教程

最后在windows的cmd中执行下面的语句开启Flask服务器
python run.py


在浏览器访问
http://localhost:5000
获得结果

虽然说这使用模板完成了HTML的解析,但是需要运行一个服务器,然后通过浏览器访问这个服务器,和我的要求不符合。
遂研究发现Flask使用render_template来进行HTML渲染
    page = render_template("index.html",
                           title = 'Home',
                           info = infomation,
                           postList = posts)

那么render_template方法能不能用来直接渲染HTML,尝试未果。 放弃

模板从天而降
查询发现Flask使用的是Jinja2引擎,所以能不能直接调用这个引擎呢,尝试未果

又找到了Mako模板引擎
Mako是一个高性能的Python模板库,它的语法和API借鉴了很多其他的模板库,如Django、Jinja2等等。

需要一个HTML模板(其实什么模板都可以,使用HTML模板渲染出来的就是HTML)和一个脚本



渲染出来的结果,大概时这样



好,下面就这个干
渲染很简单,直接建立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

 通过邮件发送

发邮件使用smtplib完成,可以使用import traceback来跟踪详细的调试信息
# 发送邮件
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的调试信息可以得到与服务器之间交互的信息
smtpObj.set_debuglevel(1)
得到大概这样子的反馈信息






好啦,到这里就结束了

以上


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值