文章目录
而这次要抓的信息里面,许多 数据项都是 JS 的,无法直接用 BeautifulSoup 直接抓取到,所以我们要使用更强大的库和工具来应对 JS。
首先介绍一下我们今天要用到的工具:
Python想必已经不用我介绍了,这里选用Python3是因为它对中文的支持更加强大;
PhantomJS可以理解成是一个模拟的浏览器,在你输入网址后跟真正的浏览器一样,执行页面上的JS语句生成我们看到的页面;
安装PhantomJS
PhantomJS的安装十分简单,去官网(http://phantomjs.org/)下载回来最新版的PhantomJS,然后随便找个地方解压缩就好了。
解压缩后如图:
打开bin文件夹,我们会看到我们要用的phantomjs.exe文件,请记住这个文件的路径。
安装selenium
selenium是Python的一个库,所以它可以通过pip安装,只要在命令行输入:
1 |
就可以完成安装啦!如下图:
第一步:简单的动态网页抓取
首先,我们要抓取报表中的各项数据,包括:云课堂销量、优酷播放量、腾讯播放量、知乎点赞量。
直接上代码(复制的时候注意不要复制上行号哦):
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="">1</span> <span class="">from</span> selenium <span class="">import</span> webdriver <span class="">2</span> <span class="">import</span> time <span class="">3</span> driver = webdriver.PhantomJS(executable_path=<span class="">"C:/phantomjs-2.1.1-windows/bin/phantomjs.exe"</span>) <span class="">4</span> driver.get(<span class="">"http://study.163.com/course/courseMain.htm?courseId=1002810012"</span>) <span class="">5</span> time.sleep(<span class="">5</span>) <span class="">6</span> data = driver.find_element_by_id(<span class="">'j-coursehead'</span>).text <span class="">7</span> a = data.find(<span class="">'\n'</span>) <span class="">8</span> b = data[a + <span class="">1</span>:].find(<span class="">'\n'</span>) <span class="">9</span> num = data[a + <span class="">1</span>:a + <span class="">1</span> + b] <span class="">10</span> driver.quit() <span class="">11</span> print(<span class="">'网易云课堂的销量为:'</span>,num) |
下面我们来逐行讲解每行代码的意思:
第一行:
1 |
<span class="">from</span> selenium <span class="">import</span> webdriver |
导入selenium库中的webdriver
第二行:
1 |
<span class="">import</span> time |
导入Python的内建库——time。time主要实现与时间有关的功能。
第三行:
1 |
driver = webdriver.PhantomJS(executable_path=<span class="">"C:/phantomjs-2.1.1-windows/bin/phantomjs.exe"</span>) |
这行的格式是:
1 |
变量名 = webdriver.PhantomJS(executable_path=<span class="">"刚才说的phantomjs.exe的地址"</span>) |
即我们指定调用PhantomJS来解析网页。
第四行:
1 |
driver.get(<span class="">"http://study.163.com/course/courseMain.htm?courseId=1002810012"</span>) |
这行的格式是:
1 |
第三行定义的变量名.get(<span class="">"目标网址"</span>) |
显然,这行的功能是使用PhantomJS来解析我们指定的网址,这里网址使用网易云课堂上我们爬虫课的网址。
第五行:
1 |
time.sleep(<span class="">5</span>) |
这行的格式是:
1 |
time.sleep(你希望推迟的秒数) |
使用time函数推迟调用线程的运行,可以理解成使程序暂停若干秒。在这里我们使用它的目的是确保上一步网页加载完成。
第六行:
1 |
data = driver.find_element_by_id(<span class="">'j-coursehead'</span>).text |
这一行的格式是:
1 |
第三行定义的变量名.查找方法(‘查找的内容’).text |
这一行用于在PhantomJS解析出来的网页上查找我们需要的内容,这里我选用的是find_element_by_class_name()
的方法,即通过class的名称来查找元素,而提供的方法还有很多,常见的有:
find_element_by_id()
通过ID来查找
find_element_by_css_selector()
通过CSS选择器查找
find_element_by_xpath()
通过xpath查找
find_element_by_link_text()
通过连接文字查找
find_element_by_tag_name()
通过tag的名称查找
有了查找方法,那我们如何获取想查找的内容呢?
用IE浏览器打开我们的目标网址,这里使用http://study.163.com/course/courseMain.htm?courseId=1002810012。
在我们想抓取的内容上(这里用课程销量)点鼠标右键,选“检查元素”,如图:
然后就会出现DOM资源管理器,并且自动定位到我们想抓取的内容所在位置上。
如图:
1 |
可以看到,上图的两个箭头处,我们既可以通过第一个箭头位置的ID进行查找,也可以通过第二个箭头处的class名称查找。
第七行、第八行、第九行:
1 2 3 |
a = data.find(<span class="">'\n'</span>) b = data[a + <span class="">1</span>:].find(<span class="">'\n'</span>) num = data[a + <span class="">1</span>:a + <span class="">1</span> + b] |
这三行用于整理我们抓取到的数据,使用的方法是字符串的分段,在之前的教程中我们已经讲过了。
第十行
1 |
driver.quit() |
在程序结束后,退出,否则会在后台一直占用系统性能的。
第十一行
1 |
print(<span class="">'网易云课堂的销量为:'</span>,num) |
程序运行一下,结果为:
(使用的IDE是Pycharm)
显然,我们成功的完成了动态内容的抓取。
刚才的演示是云课堂的销量,其他的数据爬取,比如:优酷播放量、腾讯播放量、知乎点赞量等等也是类似的,就不重复说明了。
第二步:发送邮件
每天晚上12点,把数据自动发邮件汇报,这个也交给程序来自动运行,就不用熬夜刷数据了。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<span class="">from</span> email.header <span class="">import</span> Header <span class="">from</span> email.mime.text <span class="">import</span> MIMEText <span class="">from</span> email.utils <span class="">import</span> parseaddr, formataddr <span class="">import</span> smtplib <span class=""><span class="">def</span> <span class="">_format_addr</span><span class="">(s)</span>:</span> name, addr = parseaddr(s) <span class="">return</span> formataddr((Header(name, <span class="">'utf-8'</span>).encode(), addr)) from_addr = <span class="">'寄信的邮箱地址' </span>password = <span class="">'邮箱密码' </span>to_addr = <span class="">'收信的邮箱' </span>smtp_server = <span class="">'发信邮箱的stmp服务器地址' </span>msg = MIMEText(要发送的内容, <span class="">'plain'</span>, <span class="">'utf-8'</span>) msg[<span class="">'From'</span>] = _format_addr(<span class="">'发件人 <%s>'</span> % from_addr) msg[<span class="">'To'</span>] = _format_addr(<span class="">'收件人 <%s>'</span> % to_addr) msg[<span class="">'Subject'</span>] = Header(<span class="">'邮件标题'</span>, <span class="">'utf-8'</span>).encode() server = smtplib.SMTP_SSL(smtp_server, smtp端口, timeout=<span class="">10</span>) server.set_debuglevel(<span class="">0</span>) server.login(from_addr, password) server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit() |
这里应用到了 python 的内建库:email 和 smtplib,通过 email 构建邮件,通过 smtplib 发送邮件。
这段代码只要套用就好,不做详细解释。
重点说一下三个地方:
1、邮箱密码:比如QQ和163邮箱,这里输入的并不是你的邮箱密码,而是“授权码”,在邮箱设置中可以查询到。
2、发信邮箱的smtp服务器:搜索一下很容易找到,一般类似smtp.qq.com
3、smtp端口:通常为25,但QQ邮箱为465,请根据实际情况修改,也很容易搜索到。
第三步:完整代码
注意:最后发邮件部分的代码,需要根据你自己的信息来填写替换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<span class="">from</span> selenium <span class="">import</span> webdriver <span class="">import</span> time <span class="">from</span> email.header <span class="">import</span> Header <span class="">from</span> email.mime.text <span class="">import</span> MIMEText <span class="">from</span> email.utils <span class="">import</span> parseaddr, formataddr <span class="">import</span> smtplib <span class=""><span class="">def</span> <span class="">neteasy_crawler</span><span class="">()</span>:</span> driver = webdriver.PhantomJS(executable_path=<span class="">"C:/phantomjs-2.1.1-windows/bin/phantomjs.exe"</span>) driver.get(<span class="">"http://study.163.com/course/courseMain.htm?courseId=1002810012"</span>) time.sleep(<span class="">5</span>) data = driver.find_element_by_id(<span class="">'j-coursehead'</span>).text a = data.find(<span class="">'\n'</span>) b = data[a + <span class="">1</span>:].find(<span class="">'\n'</span>) num = data[a + <span class="">1</span>:a + <span class="">1</span> + b] driver.quit() <span class="">return</span> (<span class="">'网易云课堂的销量为:'</span>+str(num)) <span class=""><span class="">def</span> <span class="">tencent_crawler</span><span class="">()</span>:</span> driver = webdriver.PhantomJS(executable_path=<span class="">"C:/phantomjs-2.1.1-windows/bin/phantomjs.exe"</span>) driver.get(<span class="">"http://v.qq.com/vplus/8bfeadf782010957b865a967fcf9e3f7/videos"</span>) time.sleep(<span class="">5</span>) data = driver.find_elements_by_class_name(<span class="">'info_inner'</span>) data_num=[] <span class="">for</span> i <span class="">in</span> data : j = int(i.text) data_num.append(j) num = sum(data_num) driver.quit() <span class="">return</span> (<span class="">'腾讯视频上的观看量为:'</span>+str(num)) <span class=""><span class="">def</span> <span class="">youku_crawler</span><span class="">()</span>:</span> driver = webdriver.PhantomJS(executable_path=<span class="">"C:/phantomjs-2.1.1-windows/bin/phantomjs.exe"</span>) driver.get(<span class="">"http://i.youku.com/i/UMTQ0MjEyMTgw"</span>) time.sleep(<span class="">5</span>) data = driver.find_element_by_class_name(<span class="">'vnum'</span>).get_attribute(<span class="">'title'</span>) num = data driver.quit() <span class="">return</span> (<span class="">'优酷视频上的观看量为:'</span>+str(num)) <span class=""><span class="">def</span> <span class="">zhihu_crawer</span><span class="">()</span>:</span> driver = webdriver.PhantomJS(executable_path=<span class="">"C:/phantomjs-2.1.1-windows/bin/phantomjs.exe"</span>) driver.get(<span class="">"https://www.zhihu.com/people/lin-qian-qian"</span>) time.sleep(<span class="">5</span>) data = driver.find_element_by_class_name(<span class="">'zm-profile-header-user-agree'</span>).text num = data[:-<span class="">2</span>] driver.quit() <span class="">return</span> (<span class="">'知乎上的点赞为:'</span>+str(num)) report_data = neteasy_crawler()+<span class="">'\n'</span>+tencent_crawler()+<span class="">'\n'</span>+youku_crawler()+<span class="">'\n'</span>+zhihu_crawer() <span class=""><span class="">def</span> <span class="">_format_addr</span><span class="">(s)</span>:</span> name, addr = parseaddr(s) <span class="">return</span> formataddr((Header(name, <span class="">'utf-8'</span>).encode(), addr)) from_addr = <span class="">'******@qq.com' </span>password = <span class="">'******' </span>to_addr = <span class="">'******@qq.com' </span>smtp_server = <span class="">'smtp.qq.com' </span>msg = MIMEText(report_data, <span class="">'plain'</span>, <span class="">'utf-8'</span>) msg[<span class="">'From'</span>] = _format_addr(<span class="">'员工 <%s>'</span> % from_addr) msg[<span class="">'To'</span>] = _format_addr(<span class="">'老板 <%s>'</span> % to_addr) msg[<span class="">'Subject'</span>] = Header(<span class="">'每日汇报'</span>, <span class="">'utf-8'</span>).encode() server = smtplib.SMTP_SSL(smtp_server, <span class="">465</span>, timeout=<span class="">10</span>) server.set_debuglevel(<span class="">0</span>) server.login(from_addr, password) server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit() |
第四步:自动运行
保存python文件为report.py
windows系统下:
进入命令提示符cmd
Win7及以下:使用at命令
1 2 |
net start schedule 这行命令用来启用Windows的计划任务 |
1 |
at 0:00 /every:Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday python report.py |
(Win8、Win10使用 SCHTASKS 命令)
linux系统下:
修改时区:
1 |
sudo cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime |
设置NTP服务器
1 |
sudo ntpdate cn.pool.ntp.org |
显示时间,检查是否正确
1 |
date |
每天 0:00,用Python执行/root/report.py文件。
编辑定时任务:
1 2 |
#crontab -e 0 0 * * * python /opt/aa.py |
保存,退出
执行
1 |
/etc/init.d/cron restart |
重启服务才能使用
到了这里,所有代码就都完成啦!开始享受程序为你工作的感觉吧~
第三方工具,像easysqlmail也可以实现
实现的方法甚多,选择适合自己的就好