网络爬虫—爬取MOOC课程信息并做一个可视化

导读:本篇文章讲解 网络爬虫—爬取MOOC课程信息并做一个可视化,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

爬取MOOC课程信息并做一个可视化

一、目标

根据你设置的关键字,也就相当于你到mooc首页的搜索引擎中要搜索的关键字,然后爬取搜索到的系列所有课程的课程名和参加该课程的人数。再以课程名为x轴,参加人数为y轴,做一个可视化。

二、知识要求

三、思路分析

1.观察网页源代码,看里面是否有关于具体课程的信息

这里,我统一以关键字为’c++程序设计基础’来进行说明:
(1)在首页输入关键字’c++程序设计基础’
在这里插入图片描述
(2)跳转页面后,点击鼠标右键,查看网页源代码,发现里面并没有关于课程的信息,我也有复制课程的网址去匹配,找到课程的id代号去匹配还是没有。这种情况,一般信息都是隐藏在js包中。

在这里插入图片描述


2.抓包分析与自动翻页

按照正常思想,接下来就是用Fiddler进行抓包分析,找到存放每个课程的信息的js包。然后,我通过抓包分析找到了存放信息的js包,但是,我发现js包的有一部分网址是随机生成的,也就是说他的js包的网址每次都是随机的!!!
这个时候,我已经想到了用PhantonJS构造模拟浏览器去解决问题。不过,此时我还是没有先用模拟浏览器,我先跑去分析构造网址,怎样实现自动翻页。
在这里插入图片描述
我规律是总结出来了,但是,无论你是构造后面哪页的网址去访问,发现,每次都会自动跳到第一页。我也是很绝望,只能用模拟浏览器技术了。


3.用PhantonJS构造模拟浏览器

都知道,PhantonJS构造模拟浏览器就相当于一个真实的浏览器,能够加载出部分的js包,你可以试一试,看看是否能够加载出存放课程信息的js包。这里,贼幸运的就是模拟浏览器加载出来了存放课程信息的js包。
测试代码:

from selenium import webdriver  # 模拟浏览器

# 打开模拟浏览器
chrome = webdriver.PhantomJS()
# 爬取该系列课程的首页
chrome.get('https://www.icourse163.org/search.htm?search=c%2B%2B%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E5%9F%BA%E7%A1%80#/')
print(chrome.page_source)

结果发现有课程信息:
在这里插入图片描述
在这里插入图片描述
(1)有课程信息就好办了,随便用xpath表达式、正则表达式、用PyQuery模块都行,就可以获取该页面所有具体课程的网址。
(2)用模拟浏览器模拟人点击下一页,实现自动翻页。再爬取下一页的所有课程的网址,直到最后一页。
(3)然后,依次用urllib或者requests模块,根据课程的网址访问所有具体的课程,爬取课程的信息。


4.可视化

用pyecharts做一个可视化。


四、爬取MOOC课程信息并做一个可视化实战

1.对代码做一下解释

  1. 将你要搜索的关键字用urllib.parse.quote()函数进行转码,转成url即网址格式
  2. 根据转码后的关键字构造要访问的系列课程的网址
  3. 用selenium与PhantomJS构造模拟浏览器,用chrome.get()函数依次访问刚刚构造的网址,也就是你要搜索的系列课程的首页
  4. 现在假如是先爬取第一个关键字名为‘c++程序设计‘的首页
  5. 然后,用chrome.page_source获取网页的源码,因为模拟浏览器能加载部分的js包,而chrome.page_source获取的源码中能加载出课程的网址,所以,我直接用PyQuery加href = code(“#j-courseCardListBox a”)直接获取了第一页(首页)的所有课程的网址
  6. 用正则表达式找到匹配下一页,看看下一页是不是最后一页显示的下一页,如果不是最后一页就用模拟浏览器的chrome.find_element_by_link_text(“下一页”).click()模拟手工点击下一页,再爬取第二页的所有课程链接,…,到了最后一页这一系列的所有课程的网址就爬完了
  7. 依次访问刚刚爬取的系列课程的所有网址,到每个课程具体页面获取参加该课程的人数。到此,第一个关键字系列课程的所有信息爬取完毕
  8. 对数据进行一个可视化
  9. 回到第4步,爬取第二个关键字的系列课程,类似的过程

2.具体代码

# 爬取mooc课程信息实战

import urllib.parse # 后面将要搜索的关键字转换为url形式会用到
import time # 用模拟浏览器操作时,每次点击下一页需要停顿5秒,会用到
import random   # ip ua
from selenium import webdriver  # 模拟浏览器
from pyquery import PyQuery as pq   # 匹配
import re   # 正则表达式需要用到
from pyecharts import Bar # 可视化需要用到

# 系列课程网址的前缀
startUrl = "http://www.icourse163.org/search.htm?search="
# 要搜索的关键字
keywds = ['计算机编程教育基础', 'c++入门知识']


'''
作用:用来根据关键字构造某系列课程的网址
参数:keywords是一个关键字列表
返回值:返回所有系列课程的首页网址
'''
def class_course_urls(keywords):
    # 将关键字转换成URL编码
    def quote(x):
        return urllib.parse.quote(x)
    keywords = list(map(quote,keywords))
    # 构造每一系列课程的网址
    urls = []
    for kws in keywords:
        urls.append(startUrl+kws)
    return urls
    
    
'''
作用:获取某系列课程中一页的所有课程的网址
参数:pageSource某页的源码
返回值:返回爬取系列课程中一页的所有课程的网址
'''
def get_course_urls(pageSource):
    # 爬取系列课程中一页的所有课程的网址
    code = pq(pageSource)
    href = code("#j-courseCardListBox a")
    urlList=[]
    # 去除掉不是课程网址的信息,即去掉不含www和含https的网址
    for i in href:
        temp = "http:" +str(code(i).attr("href"))
        if temp.__contains__("www") and temp.__contains__("course") and ("-" in temp):
            urlList.append(temp)
    # 去除重复的url地址
    urlList=list(set(urlList))
    return urlList
    
    
'''
作用:对某一系列课程进行翻页爬取该系列课程的所有课程的网址
参数:class_urls是某系列课程的首页网址
返回值:该系列课程所有课程的网址
'''
def get_class_course_urls(class_url):
    # 打开模拟浏览器
    chrome = webdriver.PhantomJS()
    # 爬取该系列课程的首页
    chrome.get(class_url)
    
    allUrl = [] # 用来存放该系列课程的所有课程的网址
    count = 1 # 用来标记当前正在爬取第几页
    while (True):
        try:
            # 用来判断是否是到最后一页的素材
            data = chrome.page_source
            pat = '<a class="th-bk-disable-gh">(.*?)</a>'
            
            print('正在爬取第', count, '页...')    # 打印正在爬取的页码
            # 调用get_course_urls()函数,将这一页的所有课程的网址添加到allUrl中
            [allUrl.append(i) for i in get_course_urls(data)]
            
            # 判断是否爬到最后一页
            d = re.compile(pat).findall(data)
            if d!=[] and count!=1:
                # 将最后一页爬取到的课程网址添加到allUrl中
                # [allUrl.append(i) for i in get_course_urls(chrome.page_source)]
                # print('正在爬取第', count+1, '页...')
                break   #爬到最后一页,跳出循环
            # 若没有爬到最后一页,就用模拟浏览器模拟人点击‘下一页’
            chrome.find_element_by_link_text("下一页").click()
            time.sleep(5)   #停顿5秒,让页面加载完全
            count += 1
        except urllib.error.HTTPError as e:
            if hasattr(e, 'code'):
                print(e.code)
            if hasattr(e, 'reason'):
                print(e.reason)
        except Exception as e:
            print(e)
    chrome.quit()
    # 对网址进行去重操作
    allUrl = list(set(allUrl))
    return allUrl
    
    
'''
作用:爬取某一具体课程的课程名和参加该课程的人数
参数:url是该课程的网址
返回值:该系列课程的课程名和参加该课程的人数
'''
def get_course_data(url):
    # 爬取该课程,获取该课程的网页源代码
    # 因为无法用urllib和request的爬取网页信息,被对方服务器积极拒绝,所以采用模拟浏览器技术
    chrome = webdriver.PhantomJS()
    chrome.get(url)
    data = chrome.page_source
    pat_name = '<span class="course-title f-ib f-vam">(.*?)</span>'
    pat_num = 'enrollCount : "(.*?)"'
    name = re.compile(pat_name).findall(data) # 返回的是列表
    num = re.compile(pat_num).findall(data) #返回的是列表
    if name == [] or num == []:
        return None, None
    else:
        return name[0], num[0]

'''
作用:将课程名和参加课程的人数进行可视化
参数:class_course 是搜索的关键字
    d_name 是课程名
    d_num 是参加该课程的人数
返回值:无
'''
def show_course_data(class_course, d_name, d_num):
    bar =Bar(class_course+"系列课程统计图", "x-课程名,y-人数")
    bar.add("课程", d_name, d_num)
    bar.show_config()
    bar.render("D:\\python\\"+class_course+".html")

def main():
    class_urls = class_course_urls(keywds)
    # 逐个爬取带关键字的课程
    alldata = []    #用来存放所有系列的课程
    for i in range(0, len(keywds)):
        data = []   # 用来存放某一系列课程的数据
        print('正在爬取带关键字【' +keywds[i]+ '】的课程...')
        urls = get_class_course_urls(class_urls[i])
        print('【' +keywds[i]+ '】系列课程爬取完毕!')
        print('该系列课程共'+str(len(urls))+'个!')
        print('这一页爬取的所有课程网址为:',urls)
        # 爬取具体某一课程的数据
        for j in range(0, len(urls)):
            # get_course_data(url)返回的是一个元组,将其添加到data中
            name, num = get_course_data(urls[j])
            # 判断内容是否为空
            if name != None and num != None:
                data.append((name, num))
            print('第'+str(j+1)+'门课程信息爬取成功!')
        alldata.append(data)
        print(alldata)
        # 对该系列课程做一个可视化
        # 将课程名放在一个列表里
        names = []
        [names.append(x[0]) for x in data]
        # 将参加课程的人数放在一个列表里
        nums = []
        [nums.append(int(x[1])) for x in data]
        print(names)
        print(nums)
        if names != [] and nums != []:
            show_course_data(keywds[i], names, nums)
        else:
            print("数据为空,无法可视化!")
        
        
if __name__ == '__main__':  
	main()

3.可视化展示

在这里插入图片描述
在这里插入图片描述

这里是引用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84788.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!