【python爬虫】爬取慕课网用户学习记录

1. 引言

由于毕业论文研究的是在线学习的相关问题,需要有用户在线学习的数据进行分析。逛了一圈,发现比较好的数据集就是KDD CUP2015的比赛数据集,不过时间有点久就弃用了,就决定还是自己一点点爬吧。

国内外有很多慕课网平台,例如国外的coursera、edx以及国内慕课网(IMOOC)、网易云课堂等。逛了一圈下来发现用户信息最丰富的就是慕课网(IMOOC)了,除了用户本身的信息如性别、位置、职业、简介、学习时长等,还有用户所学课程的学习记录,如学习进度、笔记、问答、代码分享等,最适合作为分析对象,因此本篇所述爬虫的目标就是要爬取慕课网(IMOOC)的所有用户学习记录。

2. 页面分析

慕课网用户信息.jpg

以上就是我们爬取的页面,从上到下,我们可以爬取的信息有:

用户信息

姓名:慕女神

性别:女

地点:北京

职业:全栈工程师

学习时长:39h

经验:806

积分:135

关注:99

粉丝:9999999

学习记录:

最近学习时间 课程名称 学习进度 笔记 代码 问答
2018/06/15 Flutter开发第一步-Dart编程语言入门 4% 0 0 0
2018/01/18 新一代构建工具gradle 10% 0 0 0
… … … … … … … … … … … …

用chrome的开发者工具查看数据,发现在开发者工具的Elements可以显式看到数据元素,说明数据可以直接通过下载html页面来获取。(有的数据是AJAX动态加载,这种情况就用其他方法来获取,这里不说)

image.png

再看页面的URL形式:

image6d95a8360b2ebcd9.png

头尾固定,中间ID只需要通过ID自增长的方式遍历下去就可以获得所有用户的课程学习信息。

3. 爬虫设计

3.1 工具介绍

  • python 3.7
  • requests 2.21.0 下载页面
  • lxml 解析页面
  • mysql-connector-python 8.0.13 (另外下载,pip或anaconda)数据持久化

3.2 爬取用户信息

In [1]:

1
2
3
4
5
6
7
8
9
#所需要用到的包
import requests
import time
import pandas as pd
from lxml import etree
import mysql.connector
from multiprocessing import Pool as ThreadPool
import socket
socket.setdefaulttimeout(10)

In [2]:

1
2
3
4
5
#生成待爬取的URL
urls = []
for i in range(100000, 7194872):
url = 'http://www.imooc.com/u/' + str(i) +'/courses'
urls.append(url)

In [3]:

1
2
3
4
5
#模拟浏览器访问请求
head = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
}
html = requests.get(url,headers=head,timeout=(3,7))

In [4]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#通过XPath解析请求
selector = etree.HTML(html.text)
content = selector.xpath("//html")[0]
user_id = int(url.replace('http://www.imooc.com/u/', '').replace('/courses',''))
user_name = content.xpath('//h3[@class="user-name clearfix"]/span/text()')
#若用户名为空,则说明页面不存在,因此后面的操作都需要判断用户是否存在
if user_name:
user_name = user_name[0]
user_sex = content.xpath('//p[@class="about-info"]/span/text()')
if user_sex:
user_sex = user_sex[0]
else:
user_sex = r'/'
user_time = content.xpath('//div[@class="item follows"]//em/text()')[0].replace(' ', '') #学习时长
user_exp = int(content.xpath('//div[@class="item follows"]//em/text()')[1]) #经验
user_score = int(content.xpath('//div[@class="item follows"]//em/text()')[2]) #积分
user_follows = int(content.xpath('//div[@class="item follows"]//em/text()')[3]) #关注
user_fans = int(content.xpath('//div[@class="item follows"]//em/text()')[4]) #粉丝

到此我们就抓取了用户的基本信息,接着我们看课程信息。

3.3 爬取课程学习记录

用户的课程信息分为三种情况:

  1. 用户课程信息需要翻页

imagef90adcf65970c241.png

  1. 无需翻页

image37c455863c16c3b4.png

  1. 无学习记录

imagec4569a5ad6e47895.png

对于这三种情况我们爬取的时候需要进行一个判断

In [5]:

1
2
3
4
5
6
7
8
9
10
11
last_page = content.xpath('//div[@class="page"]/a[last()]/text()') #是否包含尾页button
user_course_list = []
if last_page:
if last_page[0] == u'尾页':#需要翻页
#代码较长,完整代码见github ... ...
else:
course_num = len(content.xpath('//li[@class="course-one"]')) #该页课程数量
if course_num == 0:#无学习记录
pass
else:#有记录,不需要翻页
#代码较长,完整代码见github ... ...

3.4 数据持久化

由于爬取的数据较大,我们需要把数据存储起来,因此我们把爬下来的记录存储在mysql中

In [5]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def creat_MysqlDB():
mydb = mysql.connector.connect(
host="localhost",
user="root",
passwd="123456",
database="MOOC"
)
return mydb
mydb = creat_MysqlDB()
sql = "INSERT INTO user_learn_info (user_id,user_name,user_sex,user_time,user_exp,\
user_score,user_follows,user_fans,course_id,course_name,last_time,\
process,note,code,qna) VALUES \
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,%s, %s, %s, %s, %s)"
val = (user_id,user_name,user_sex,user_time,user_exp,user_score,user_follows,user_fans
,course_id,course_name,last_time,process,note,code,qna)
mycursor = mydb.cursor()
mycursor.execute(sql, val)
mydb.commit()

3.5 使用多进程提高爬取效率

In [5]:

1
2
3
4
5
from multiprocessing import Pool as ThreadPool
pool = ThreadPool(8) #进程数
pool.map(getsource, urls) #对每个URL进行爬取
pool.close() #关闭进程池
pool.join() #主线程,等待子线程运行完毕

4. 结果

image95923e93a445f23b.png

这是爬取过程中数据库表记录,可以看到已经爬取了两百多万条记录,爬虫稳定运行,等着也是等着,写篇博客记录一下,完整代码在github上,见——>>完整代码