Python爬取Coursera课程资源的详细过程

有时候我们需要把一些经典的东西收藏起来,时时回味,而Coursera上的一些课程无疑就是经典之作。Coursera中的大部分完结课程都提供了完整的配套教学资源,包括ppt,视频以及字幕等,离线下来后会非常便于学习。很明显,我们不会去一个文件一个文件的下载,只有傻子才那么干,程序员都是聪明人!

那我们聪明人准备怎么办呢?当然是写一个脚本来批量下载了。首先我们需要分析一下手工下载的流程:登录自己的Coursera账户(有的课程需要我们登录并选课后才能看到相应的资源),在课程资源页面里,找到相应的文件链接,然后用喜欢的工具下载。

很简单是吧?我们可以用程序来模仿以上的步骤,这样就可以解放双手了。整个程序分为三个部分就可以了:

登录Coursera;在课程资源页面里面找到资源链接;根据资源链接选择合适的工具下载资源。

下面就来具体的实现以下吧!

登录

刚开始时自己并没有添加登录模块,以为访客就可以下载相应的课程资源,后来在测试comnetworks-002这门课程时发现访客访问资源页面时会自动跳转到登录界面,下图是chrome在隐身模式访问该课程资源页面时的情况。

要想模拟登录,我们先找到登录的页面,然后利用google的Developer Tools分析账号密码是如何上传到服务器的。

我们在登录页面的表单中填入账号密码,然后点击登录。与此同时,我们需要双眼紧盯Developer Tools——Network,找到提交账号信息的url。一般情况下,如果要向服务器提交信息,一般都用post方法,这里我们只需要先找到Method为post的url。悲剧的是,每次登录账号时,Network里面都找不到提交账户信息的地址。猜测登录成功后,直接跳转到登录成功后的页面,想要找的内容一闪而过了。

于是就随便输入了一组账号密码,故意登录失败,果真找到了post的页面地址,如下图:

地址为:https://accounts.coursera.org/api/v1/login。为了知道向服务器提交了哪些内容,进一步观察post页面中表单中内容,如下图:

我们看到一共有三个字段:

email:账号的注册邮箱password:账号密码webrequest:附加的字段,值为true。

接下来就动手写吧,我选择用python的Requests库来模拟登录,关于Requests官网是这样介绍的。

Requests is an elegant and simple HTTP library for Python, built for human beings.

事实上requests用起来确实简单方便,不亏是专门为人类设计的http库。requests提供了Session对象,可以用来在不同的请求中传递一些相同的数据,比如在每次请求中都携带cookie。

初步的代码如下:

signin_url = "https://accounts.coursera.org/api/v1/login"logininfo = {"email": "...",             "password": "...",             "webrequest": "true"             }
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) "              "AppleWebKit/537.36 (KHTML, like Gecko) "              "Chrome/36.0.1985.143 Safari/537.36")
post_headers = {"User-Agent": user_agent,                "Referer": "https://accounts.coursera.org/signin"                }coursera_session = requests.Session()
login_res = coursera_session.post(signin_url,                                  data=logininfo,                                  headers=post_headers,                                  )if login_res.status_code == 200:    print "Login Successfully!"else:    print login_res.text

将表单中提交的内容存放在字典中,然后作为data参数传递给Session.post函数。一般情况下,最好是加上请求User-AgentReferer等请求头部,User-Agent用来模拟浏览器请求,Referer用来告诉服务器我是从referer页面跳转到请求页面的,有时候服务器会检查请求的Referer字段来保证是从固定地址跳到当前请求页的。

上面片段的运行结果很奇怪,显示如下信息:Invalid CSRF Token。后来在github上面搜索到一个Coursera的批量下载脚本,发现人家发送页面请求时headers多了XCSRF2Cookie, XCSRF2Token, XCSRFToken, cookie4个字段。于是又重新看了一下post页面的请求头部,发现确实有这几个字段,估计是服务器端用来做一些限制的。

用浏览器登录了几次,发现XCSRF2Token, XCSRFToken是长度为24的随机字符串,XCSRF2Cookie为"csrf2_token_"加上长度为8的随机字符串。不过一直没搞明白Cookie是怎么求出来的,不过看github上面代码,Cookie似乎只是"csrftoken"和其他三个的组合,试了一下竟然可以。

在原来的代码上添加以下部分就足够了。

def randomString(length):    return ''.join(random.choice(string.letters + string.digits) for i in xrange(length))XCSRF2Cookie = 'csrf2_token_%s' % ''.join(randomString(8))XCSRF2Token = ''.join(randomString(24))XCSRFToken = ''.join(randomString(24))cookie = "csrftoken=%s; %s=%s" % (XCSRFToken, XCSRF2Cookie, XCSRF2Token)post_headers = {"User-Agent": user_agent,                "Referer": "https://accounts.coursera.org/signin",                "X-Requested-With": "XMLHttpRequest",                "X-CSRF2-Cookie": XCSRF2Cookie,                "X-CSRF2-Token": XCSRF2Token,                "X-CSRFToken": XCSRFToken,                "Cookie": cookie                }

至此登录功能初步实现。

分析资源链接

登录成功后,我们只需要get到资源页面的内容,然后过滤出自己需要的资源链接就行了。资源页面的地址很简单,为https://class.coursera.org/name/lecture,其中name为课程名称。比如对于课程comnetworks-002,资源页面地址为https://class.coursera.org/comnetworks-002/lecture。

抓取到页面资源后,我们需要分析html文件,这里选择使用BeautifulSoup。BeautifulSoup是一个可以从HTML或XML文件中提取数据的Python库,相当强大。具体使用官网上有很详细的文档,这里不再赘述。在使用BeautifulSoup前,我们还得找出资源链接的规律,方便我们过滤。

其中课程每周的总题目为class=course-item-list-header的div标签下,每周的课程均在class=course-item-list-section-list的ul标签下,每节课程在一个li标签中,课程资源则在li标签中的div标签中。

查看了几门课程之后,发现过滤资源链接的方法很简单,如下:

ppt和ppt资源:用正则表达式匹配链接;字幕资源:找到title="Subtitles (srt)"的标签,取其href属性;视频资源:找到title="Video (MP4)"的标签,取其href属性即可。

字幕和视频也可以用正则表达式过滤,不过用BeautifulSoup根据title属性来匹配,有更好的易读性。而ppt和pdf资源,没有固定的title属性,只好利用正则表达式来匹配。

具体代码如下:

soup = BeautifulSoup(content)chapter_list = soup.find_all("div", class_="course-item-list-header")lecture_resource_list = soup.find_all("ul", class_="course-item-list-section-list")ppt_pattern = re.compile(r'https://[^"]*\.ppt[x]?')pdf_pattern = re.compile(r'https://[^"]*\.pdf')for lecture_item, chapter_item in zip(lecture_resource_list, chapter_list):    # weekly title    chapter = chapter_item.h3.text.lstrip()    for lecture in lecture_item:        lecture_name = lecture.a.string.lstrip()        # get resource link        ppt_tag = lecture.find(href=ppt_pattern)        pdf_tag = lecture.find(href=pdf_pattern)        srt_tag = lecture.find(title="Subtitles (srt)")        mp4_tag = lecture.find(title="Video (MP4)")        print ppt_tag["href"], pdf_tag["href"]        print srt_tag["href"], mp4_tag["href"]

下载资源

既然已经得到了资源链接,下载部分就很容易了,这里我选择使用curl来下载。具体思路很简单,就是输出curl resource_link -o file_name到一个种子文件中去,比如到feed.sh中。这样只需要给种子文件执行权限,然后运行种子文件即可。

为了便于归类课程资源,可以为课程每周的标题建立一个文件夹,之后该周的所有课程均下载在该目录下。为了方便我们快速定位到每节课的所有资源,可以把一节课的所有资源文件均命名为课名.文件类型。具体的实现比较简单,这里不再给出具体程序了。可以看一下一个测试例子中的feed.sh文件,部分内容如下:

mkdir 'Week 1: Introduction, Protocols, and Layering'cd 'Week 1: Introduction, Protocols, and Layering'curl https://d396qusza40orc.cloudfront.net/comnetworks/lect/1-readings.pdf -o '1-1 Goals and Motivation (15:46).pdf'curl https://class.coursera.org/comnetworks-002/lecture/subtitles?q=25_en&format=srt -o '1-1 Goals and Motivation (15:46).srt'curl https://class.coursera.org/comnetworks-002/lecture/download.mp4?lecture_id=25 -o '1-1 Goals and Motivation (15:46).mp4'curl https://d396qusza40orc.cloudfront.net/comnetworks/lect/1-readings.pdf -o '1-2 Uses of Networks (17:12).pdf'curl https://class.coursera.org/comnetworks-002/lecture/subtitles?q=11_en&format=srt -o '1-2 Uses of Networks (17:12).srt'curl https://class.coursera.org/comnetworks-002/lecture/download.mp4?lecture_id=11 -o '1-2 Uses of Networks (17:12).mp4'

到这里为止,我们已经成功完成爬取Coursera课程资源的目标,具体的代码放在gist上。使用时,我们只需要运行程序,并把课程名称作为参数传递给程序就可以了(这里的课程名称并不是整个课程的完整名字,而是在课程介绍页面地址中的缩略名字,比如Computer Networks这门课,课程名称是comnetworks-002)。

其实,这个程序可以看做一个简单的小爬虫程序了,下面粗略介绍下爬虫的概念。

一点都不简单的爬虫

关于什么是爬虫,wiki上是这样说的

A Web crawler is an Internet bot that systematically browses the World Wide Web, typically for the purpose of Web indexing.

爬虫的总体架构图如下(图片来自wiki):

简单来说,爬虫从Scheduler中获取初始的urls,下载相应的页面,存储有用的数据,同时分析该页面中的链接,如果已经访问就pass,没访问的话加入到Scheduler中等待抓取页面。

当然有一些协议来约束爬虫的行为规范,比如许多网站都有一个robots.txt文件来规定网站哪些内容可以被爬取,哪些不可以。

每个搜索引擎背后都有一个强大的爬虫程序,把触角伸到网络中的所有角落,不断去收集有用信息,并建立索引。这种搜索引擎级别的爬虫实现起来非常复杂,因为网络上的页面数量太过庞大,只是遍历他们就已经很困难了,更不要说去分析页面信息,并建立索引了。

实际应用中,我们只需要爬取特定站点,抓取少量的资源,这样实现起来简单很多。不过仍然有许多让人头疼的问题,比如许多页面元素是javascript生成的,这时候我们需要一个javascript引擎,渲染出整个页面,再加以过滤。

更糟糕的是,许多站点都会用一些措施来阻止爬虫爬取资源,比如限定同一IP一段时间的访问次数,或者是限制两次操作的时间间隔,加入验证码等等。绝大多数情况下,我们不知道服务器端是如何防止爬虫的,所以要想让爬虫工作起来确实挺难的。

(0)

相关推荐

  • 通过抓取淘宝评论为例讲解Python爬取ajax动态生成的数据(经典)

    在学习python的时候,一定会遇到网站内容是通过 ajax动态请求.异步刷新生成的json数据 的情况,并且通过python使用之前爬取静态网页内容的方式是不可以实现的,所以这篇文章将要讲述如果在python中爬取ajax动态生成的数据. 至于读取静态网页内容的方式,有兴趣的可以查看本文内容. 这里我们以爬取淘宝评论为例子讲解一下如何去做到的. 这里主要分为了四步: 一 获取淘宝评论时,ajax请求链接(url) 二 获取该ajax请求返回的json数据 三 使用python解析json数据

  • Python爬虫:通过关键字爬取百度图片

    使用工具:Python2.7 点我下载 scrapy框架 sublime text3 一.搭建python(Windows版本)  1.安装python2.7 ---然后在cmd当中输入python,界面如下则安装成功  2.集成Scrapy框架----输入命令行:pip install Scrapy 安装成功界面如下: 失败的情况很多,举例一种: 解决方案: 其余错误可百度搜索. 二.开始编程. 1.爬取无反爬虫措施的静态网站.例如百度贴吧,豆瓣读书. 例如-<桌面吧>的一个帖子https:

  • Python爬虫模拟登录带验证码网站

    爬取网站时经常会遇到需要登录的问题,这是就需要用到模拟登录的相关方法.python提供了强大的url库,想做到这个并不难.这里以登录学校教务系统为例,做一个简单的例子. 首先得明白cookie的作用,cookie是某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据.因此我们需要用Cookielib模块来保持网站的cookie. 这个是要登陆的地址 http://202.115.80.153/ 和验证码地址 http://202.115.80.153/CheckCode.

  • python实现爬取千万淘宝商品的方法

    本文实例讲述了python实现爬取千万淘宝商品的方法.分享给大家供大家参考.具体实现方法如下: import time import leveldb from urllib.parse import quote_plus import re import json import itertools import sys import requests from queue import Queue from threading import Thread URL_BASE = 'http://s

  • Python 爬虫爬取指定博客的所有文章

    自上一篇文章 Z Story : Using Django with GAE Python 后台抓取多个网站的页面全文 后,大体的进度如下: 1.增加了Cron: 用来告诉程序每隔30分钟 让一个task 醒来, 跑到指定的那几个博客上去爬取最新的更新 2.用google 的 Datastore 来存贮每次爬虫爬下来的内容..只存贮新的内容.. 就像上次说的那样,这样以来 性能有了大幅度的提高: 原来的每次请求后, 爬虫才被唤醒 所以要花大约17秒的时间才能从后台输出到前台而现在只需要2秒不到

  • 使用Python中的cookielib模拟登录网站

    前面简单提到了 Python 模拟登录的程序,但是没写清楚,这里再补上一个带注释的 Python 模拟登录的示例程序.简单说一下流程:先用cookielib获取cookie,再用获取到的cookie,进入需要登录的网站. # -*- coding: utf-8 -*- # !/usr/bin/python import urllib2 import urllib import cookielib import re auth_url = 'http://www.nowamagic.net/' h

  • Python使用Scrapy爬取妹子图

    Python Scrapy爬虫,听说妹子图挺火,我整站爬取了,上周一共搞了大概8000多张图片.和大家分享一下. 核心爬虫代码 # -*- coding: utf-8 -*- from scrapy.selector import Selector import scrapy from scrapy.contrib.loader import ItemLoader, Identity from fun.items import MeizituItem class MeizituSpider(sc

  • python爬取网站数据保存使用的方法

    编码问题因为涉及到中文,所以必然地涉及到了编码的问题,这一次借这个机会算是彻底搞清楚了.问题要从文字的编码讲起.原本的英文编码只有0~255,刚好是8位1个字节.为了表示各种不同的语言,自然要进行扩充.中文的话有GB系列.可能还听说过Unicode和UTF-8,那么,它们之间是什么关系呢?Unicode是一种编码方案,又称万国码,可见其包含之广.但是具体存储到计算机上,并不用这种编码,可以说它起着一个中间人的作用.你可以再把Unicode编码(encode)为UTF-8,或者GB,再存储到计算机

  • python制作爬虫爬取京东商品评论教程

    本篇文章是python爬虫系列的第三篇,介绍如何抓取京东商城商品评论信息,并对这些评论信息进行分析和可视化.下面是要抓取的商品信息,一款女士文胸.这个商品共有红色,黑色和肤色三种颜色, 70B到90D共18个尺寸,以及超过700条的购买评论. 京东商品评论信息是由JS动态加载的,所以直接抓取商品详情页的URL并不能获得商品评论的信息.因此我们需要先找到存放商品评论信息的文件.这里我们使用Chrome浏览器里的开发者工具进行查找. 具体方法是在商品详情页点击鼠标右键,选择检查,在弹出的开发者工具界

  • Python实现爬取知乎神回复简单爬虫代码分享

    看知乎的时候发现了一个 "如何正确地吐槽" 收藏夹,里面的一些神回复实在很搞笑,但是一页一页地看又有点麻烦,而且每次都要打开网页,于是想如果全部爬下来到一个文件里面,是不是看起来很爽,并且随时可以看到全部的,于是就开始动手了. 工具 1.Python 2.7 2.BeautifulSoup 分析网页 我们先来看看知乎上该网页的情况 网址:,容易看到,网址是有规律的,page慢慢递增,这样就能够实现全部爬取了. 再来看一下我们要爬取的内容: 我们要爬取两个内容:问题和回答,回答仅限于显示

  • Python实现爬取需要登录的网站完整示例

    本文实例讲述了Python爬取需要登录的网站实现方法.分享给大家供大家参考,具体如下: import requests from lxml import html # 创建 session 对象.这个对象会保存所有的登录会话请求. session_requests = requests.session() # 提取在登录时所使用的 csrf 标记 login_url = "https://bitbucket.org/account/signin/?next=/" result = se

随机推荐