用scrapy爬虫抓取慕课网课程数据详细步骤

2017 年 8 月 17 日 数据挖掘入门与实战 要学习更多点☞



数据挖掘入门与实战  公众号: datadw


声明:本文根据慕课网公开数据爬取,仅作为数据分析学习参考。

爬虫代码获取,在公众号里回复关键字“慕课”即可。



关于如何安装scrapy框架,可以参考这篇文章


史上最完全Mac安装Scrapy指南

http://www.jianshu.com/p/a03aab073a35


超简单Windows安装Scrapy (仅需一步)

http://www.cnblogs.com/lfoder/p/6565088.html

 
这里使用的是Python2.7

例子的目标就是抓取慕课网的课程信息


流程分析


抓取内容

例子要抓取这个网页http://www.imooc.com/course/list
要抓取的内容是全部的课程名称,图片URL,课程图片,课程人数,课程简介,课程URL ,课程评分,课程难度,课程时长


这样的:



我们要抓取的是这一部分

或者说抓取其中的每一个课程div

#response是爬虫请求获取的网页资源,下面的代码可以帮助我们获得每一个课程div
response.xpath('.//div[@class="course-card-container"]')


scrapy 支持使用Xpath网页元素定位器

想抓取哪个数据,可以用xpath定位它的位置,下面介绍几个实用的插件:

使用火狐浏览器,安装两个扩展插件FirebugFirePath



安装好之后,Firebug的作用是方便获取到目标位置的源码,使用方法是:

鼠标移动到网页中你要获取的数据的位置,右键单击,然后选择“使用Firebug查看元素”,结果如下:



接下来可以用FirePath 调试你的xpath表达式,方法是:

打开目标网页,在任意位置右键,选择“Inspect in FirePath ”,结果如下:



图中的红色框就是xpath表达式,直接右击网页生成的xpath表达式在爬虫里用不了,需要改改。这里列举几个常用,且够用的七个符号:

以下面三句为例:

response.xpath('.//div[@class="course-card-container"]')

 

box.xpath('.//@href').extract()[0]


box.xpath('.//h3/text()').extract()[0]


英文 句号“.”  表示当前对象里面的内容,比如上面就是指response和box里面的内容;


双斜杠 //  表示获取所有的指定元素,比如上面第一句就是在esponse内容里取所有的指定class属性值为"course-card-container"的div标签


a[@b='c']  表示指定获取属性b的值为c的a标签,


如果是单斜杠 /  就是取一个,

@ 是指定属性

box.xpath('.//@href') 这句就是box内容里面获取所有的包含href属性的html标签,

text()就是取html标签里面的文本内容


最后加个.extract() 其实是将提取的内容转换成python 的list列表结构,在scrapy里必须加这个,否则报错。


只要熟悉了上面七个符号的用法,就可以获取任何你想定位的内容。写好xpath表达式后,可以放到FirePath里调试,比如

response.xpath('.//div[@class="course-card-container"]')


这里response存放的是爬虫打开网页获取的内容,用火狐浏览器手动打开该网页,将这句

.//div[@class="course-card-container"]

xpath表达式copy放到FirePath里,按回车,结果如下:



如果想在获取结果里面继续获取下一层的东西,就直接在刚那句后面加xpath表达式,比如,我想获取所有h3标签里面的文本内容

.//div[@class="course-card-container"]//h3/text()

这样我们就获取到了页面里面课程的标题~,这个xpath表达式就可以放到scprapy爬虫里面啦~


其他的网页数据的定位也是类似操作:通过Firebug查看目标数据的源码,通过FirePath 调试xpath表达式。


获取的信息如下:

#获取课程URL
item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0]
#获取课程标题
item['title'] = box.xpath('.//h3/text()').extract()[0]
#获取课程图片URL
item['image_url'] = box.xpath('.//@src').extract()[0]
# 获取div中的学生人数
item['student'] = box.xpath('.//div[@class="course-card-info"]/span[2]/text()').extract()[0]
# 获取div中的课程简介
item['introduction'] = box.xpath('.//p/text()').extract()[0].strip()


工作流程

 


工作流程

Scrapy框架抓取的基本流程是这样(随便画了一下,不要纠结)





工程建立

在控制台模式下(windows系统用cmd进入命令行),用cd 命令进入你要建立工程的文件夹,然后执行如下命令创建工程

scrapy startproject scrapytest


这里的scrapytest是工程名框架会自动在当前目录下创建一个同名的文件夹,工程文件就在里边。



目录分析

目录结构如下图。

scrapy.cfg: 项目的配置文件
scrapytest/: 该项目的python模块。之后您将在此加入代码。
scrapytest/items.py: 项目中的item文件.
scrapytest/pipelines.py: 项目中的pipelines文件.
scrapytest/settings.py: 项目的设置文件.
scrapytest/spiders/: 放置spider代码的目录.


创建一个爬虫

下面按步骤讲解如何编写一个简单的爬虫。

我们要编写爬虫,首先是创建一个Spider

我们在scrapytest/spiders/目录下创建一个文件MySpider.py

文件包含一个MySpider类,它必须继承scrapy.Spider类。

同时它必须定义一下三个属性:

-name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。
-start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。
-parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。


创建完成后MySpider.py的代码如下

# -*- coding: utf-8 -*-
import scrapy
class MySpider(scrapy.Spider):
name = "MySpider"

   allowed_domains = ["imooc.com"]

start_urls = ["http://www.imooc.com/course/list"]

def parse(self, response):
       pass


定义爬取项目

创建完了Spider文件,先不急着编写爬取代码
我们先定义一个容器保存要爬取的数据。

这样我们就用到了Item
为了定义常用的输出数据,Scrapy提供了Item类。Item对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于词典(dictionary-like)的API以及用于声明可用字段的简单语法。

我们在工程目录下可以看到一个items文件,我们可以更改这个文件或者创建一个新的文件来定义我们的item。

这里,我们在同一层创建一个新的item文件CourseItems.py

CourseItems.py的代码如下

# -*- coding: utf-8 -*-
#引入文件
import scrapy

class CourseItem(scrapy.Item):
#课程标题
   title = scrapy.Field()
#课程url
   url = scrapy.Field()
#课程标题图片
   image_url = scrapy.Field()
#课程描述
   introduction = scrapy.Field()
#学习人数
   student = scrapy.Field()
#课程标签
   catycray = scrapy.Field()
#课程难度
   degree = scrapy.Field()
#课程时长
   hour =scrapy.Field()

#课程评分
   score=scrapy.Field()


根据如上的代码,我们创建了一个名为courseItem的容器,用来保存、抓取的信息,
title->课程标题, url->课程url, image_url->课程标题图片, introduction->课程描述, student->学习人数





编写Spider代码

定义了item后我们就能进行爬取部分的工作了。

为了简单清晰,我们先抓取一个页面中的信息。


首先我们编写爬取代码

我们在上文说过,爬取的部分在MySpider类的parse()方法中进行。
parse()方法负责处理response并返回处理的数据以及(/或)跟进的URL。
该方法及其他的Request回调函数必须返回一个包含 Request 及(或) Item 的可迭代的对象。


我们在之前创建的MySpider.py中编写如下代码。


注意和上边MySpider.py的区别


# -*- coding: utf-8 -*-
import scrapy
import urllib

from scrapytest.CourseItems import CourseItem


class MySpider(scrapy.Spider):

    name = "MySpider"

    allowed_domains = ["imooc.com"]
   
    start_urls = ["http://www.imooc.com/course/list"]

   

    def parse(self, response):
 
        item = CourseItem()
      
        for box in response.xpath('.//div[@class="course-card-container"]'):
    
            item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0]
     
            item['title'] = box.xpath('.//h3/text()').extract()[0]
   
            item['image_url'] = box.xpath('.//@src').extract()[0]
            #获取div中的学生人数
            item['student'] = box.xpath('.//div[@class="course-card-info"]/span[2]/text()').extract()[0]
            #获取div中的课程简介
            item['introduction'] = box.xpath('.//p/text()').extract()[0].strip()
            #是否有多个
            if len(box.xpath('.//div[@class="course-label"]/label/text()').extract())==1:

                item['catycray'] = box.xpath('.//div[@class="course-label"]/label/text()').extract()[0]

            elif len(box.xpath('.//div[@class="course-label"]/label/text()').extract())==2:
                item['catycray'] = box.xpath('.//div[@class="course-label"]/label/text()').extract()[0]+' '+ box.xpath('.//div[@class="course-label"]/label/text()').extract()[1]
            elif len(box.xpath('.//div[@class="course-label"]/label/text()').extract())==3:
                item['catycray'] = box.xpath('.//div[@class="course-label"]/label/text()').extract()[0]+' '+box.xpath('.//div[@class="course-label"]/label/text()').extract()[1]+' '+ box.xpath('.//div[@class="course-label"]/label/text()').extract()[2]
            else :
                item['catycray'] = ''
            
            #下载图片
            #urllib.urlretrieve(item['image_url'],'pic/'+item['title']+'.jpg')
            
            
         

            #返回信息
            yield scrapy.Request(item['url'], callback=self.parseNest,meta=item)
        
    #课程详情页
    def parseNest(self, response):
        item = response.meta
        #print item
        item['degree'] = response.xpath('.//div[@class="static-item l"]/span[@class="meta-value"]/text()').extract()[0]
         
        item['hour'] =response.xpath('.//div[@class="static-item l"]/span[@class="meta-value"]/text()').extract()[1]

        item['score']=response.xpath('.//div[@class="static-item l score-btn"]/span[@class="meta-value"]/text()').extract()[0]

        yield item

        #url跟进开始
        #获取下一页的url信息
        #url = response.xpath("//a[contains(text(),'下一页')]/@href").extract()
        #if url :
            #将信息组合成下一页的url
            #page = 'http://www.imooc.com' + url[0]
            #返回url


        for x in xrange(2,32):
            page='http://www.imooc.com/course/list?page='+str(x)
            yield scrapy.Request(page, callback=self.parse)
        #url跟进结束


注:这里用到了xpath方式来获取页面信息,这里不做过多介绍,可以参考网上的xpath教程来自己学习。


在parse()方法中response参数返回一个下载好的网页信息,我们然后通过xpath来寻找我们需要的信息。
在scrapy框架中,可以使用多种选择器来寻找信息,这里使用的是xpath,同时我们也可以使用BeautifulSoup,lxml等扩展来选择,而且框架本身还提供了一套自己的机制来帮助用户获取信息,就是Selectors。
因为本文只是为了入门所以不做过多解释。

在执行完以上步骤之后,我们可以运行一下爬虫,看看是否出错。

在命令行下进入工程文件夹,然后运行

scrapy crawl MySpider

如果操作正确会显示如下信息。


上面信息表示,我们已经获取了信息,接下来我们开始进行信息的储存。



使用Pipeline处理数据

当我们成功获取信息后,要进行信息的验证、储存等工作,这里以储存为例。
当Item在Spider中被收集之后,它将会被传递到Pipeline,一些组件会按照一定的顺序执行对Item的处理。
Pipeline经常进行一下一些操作:
   清理HTML数据
   验证爬取的数据(检查item包含某些字段)
   查重(并丢弃)
   将爬取结果保存到数据库中


将数据储存在json文件的操作:


首先在scrapytest/目录下建立一个文件MyPipelines.py

MyPipelines.py代码如下


# -*- coding: utf-8 -*-
#引入文件
from scrapy.exceptions import DropItem
import json
import codecs

class MyPipeline(object):
    def __init__(self):

        #打开文件
        self.file = open('data.json', 'w')
  self.file =codecs.open('data.json', 'w', encoding='utf-8')
    # #该方法用于处理数据
 def process_item(self, item, spider):
    #     #读取item中的数据
       
         line = json.dumps(dict(item), ensure_ascii=False) + "\n"
         #写入文件
         self.file.write(line)
         #返回item
         return item

要使用Pipeline,首先要注册Pipeline

找到settings.py文件,这个文件时爬虫的配置文件

在其中添加



ITEM_PIPELINES = {
    'scrapytest.MyPipelines.MyPipeline': 1,
}


上面的代码用于注册Pipeline,其中scrapytest.MyPipelines.MyPipeline为你要注册的类,右侧的’1’为该Pipeline的优先级,范围1~1000,越小越先执行。

进行完以上操作,我们的一个最基本的爬取操作就完成了

这时我们再运行

scrapy crawl MySpider

就可以在项目根目录下发现data.json文件,里面存储着爬取的课程信息。




这样一个简单的爬虫就完成了。



存入mysql数据库

1,先在数据库建好跟item相同字段的表



2.安装python 的MySQLdb模块

pip install mysql-python


参考:

http://www.cnblogs.com/rwxwsblog/p/4572367.html


3.修改MyPipelines.py代码如下:


# -*- coding: utf-8 -*-
#引入文件
from scrapy.exceptions import DropItem

import MySQLdb
import MySQLdb.cursors
from twisted.enterprise import adbapi

class MyPipeline(object):
    def __init__(self):

        self.conn = MySQLdb.connect(user='root', passwd='123456', db='test', host='127.0.0.1', charset="utf8", use_unicode=True)
        self.cursor = self.conn.cursor()

 

    #pipeline默认调用
    def process_item(self, item, spider):

        try:
            self.cursor.execute("insert into mooc(title, student, catycray, degree, hour,score,introduction,url,image_url) values(%s, %s, %s, %s, %s, %s, %s, %s, %s)", (item['title'], item['student'], item['catycray'], item['degree'], item['hour'], item['score'], item['introduction'], item['url'], item['image_url']))
            self.conn.commit()
     
     
        except MySQLdb.Error, e:
            print "Error %d: %s" % (e.args[0], e.args[1])
        return item
            
    #异常处理
    def _handle_error(self, failue, item, spider):
        log.err(failure)
    该方法在spider被开启时被调用。
    def open_spider(self, spider):
        pass
    #该方法在spider被关闭时被调用。
    def close_spider(self, spider):
        pass


然后再次运行爬虫,下载数据如下:




url跟进

在上面我们介绍了如何进行简单的单页面爬取,但是我们可以发现慕课网的课程是分布在去多个页面的,所以为了完整的爬取信息课程信息,我们需要进行url跟进。

为了完成这个目标需要对MySpider.py文件进行添加:

  

#url跟进结束


for x in xrange(2,32):
            page='http://www.imooc.com/course/list?page='+str(x)
            yield scrapy.Request(page, callback=self.parse)
       



修改成功后就可以自动进行url跟进了。



下载图片

在上文我们爬取了慕课网全部的课程信息,但是每个课程的标题图片我们只获得了url并没有下载下了,这里我们进行图片下载的编写。

首先我们在CourseItems.py文件中添加如下属性

#图片地址image_path = scrapy.Field()

因为我们要下载图片,所以需要用这个属性用来保存下载地址。

接下来我们需要在MySpider.py添加 :


import urllib

urllib.urlretrieve(item['image_url'],'pic/'+item['title']+'.jpg')



urllib.urlretrieve(url,path)函数需要两个参数,一个是图片的地址url,另一个就保存路径。


下载图片如下:





总结

把多余的文件删除后的目录结构

上面的处理结束后我们就成功的抓取了慕课网的全部课程信息了。

以上就是Scrapy入门小例子了。


有人会觉得在控制台运行scrapy 不够方便,想在IDE环境里运行和调试,比如pycharm

配置步骤如下:

用pycharm 打开scrapy项目所在文件夹,新建一个begin.py文件,添加代码:

# -*- coding: utf-8 -*-
from scrapy.cmdline import execute
execute()

然后点击pycharm界面上"run"小三角按钮旁边的Edit Configuration,打开后点击左上角的“+”号,添加一个python配置,Script框里选择刚刚建好的begin.py文件,

Script parameters 框 填入crawl MySpider ,其实就是crawl +爬虫名字,其他配置选项默认,点ok,就可以运行爬虫了。

如下:


以上,把一个经典爬虫的所有过程都讲了,会了这些可以爬取大部分网页了,可以优化地方就是 模拟浏览器,多进程等,这些需要具备一定的基础。过几天再来分享一个更强大,更简单易用 的爬虫框架--pyspider,可定时,可实时,可多线程爬取,支持开发复杂的爬虫系统,有兴趣可以一起关注。

爬虫代码获取,在公众号里回复关键字“慕课”即可。


人工智能AI与大数据技术实战

搜索添加微信公众号:weic2c


长按图片,识别二维码,点关注



数据挖掘入门与实战

搜索添加微信公众号:datadw


教你机器学习,教你数据挖掘


长按图片,识别二维码,点关注



登录查看更多
0

相关内容

Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。
【2020新书】实战R语言4,323页pdf
专知会员服务
100+阅读 · 2020年7月1日
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
161+阅读 · 2020年5月14日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
117+阅读 · 2020年5月10日
 第八届中国科技大学《计算机图形学》暑期课程课件
专知会员服务
55+阅读 · 2020年3月4日
【经典书】Python计算机视觉编程,中文版,363页pdf
专知会员服务
139+阅读 · 2020年2月16日
【阿里技术干货】知识结构化在阿里小蜜中的应用
专知会员服务
96+阅读 · 2019年12月14日
ExBert — 可视化分析Transformer学到的表示
专知会员服务
31+阅读 · 2019年10月16日
GitHub 热门:各大网站的 Python 爬虫登录汇总
机器学习算法与Python学习
9+阅读 · 2019年3月20日
抖音爬虫
专知
3+阅读 · 2019年2月11日
比Selenium快100倍的方法爬东方财富网财务报表
程序人生
8+阅读 · 2018年10月31日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
干货 | Python 爬虫的工具列表大全
机器学习算法与Python学习
10+阅读 · 2018年4月13日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
【python 自然语言处理】对胡歌【猎场】电视剧评论进行情感值分析
Python3爬虫之入门和正则表达式
全球人工智能
7+阅读 · 2017年10月9日
使用 Python 绘制《星战》词云
Datartisan数据工匠
3+阅读 · 2017年8月31日
33款可用来抓数据的开源爬虫软件工具 (推荐收藏)
数据科学浅谈
7+阅读 · 2017年7月29日
Learning to See Through Obstructions
Arxiv
7+阅读 · 2020年4月2日
Arxiv
8+阅读 · 2018年5月1日
Arxiv
8+阅读 · 2018年1月12日
Arxiv
4+阅读 · 2016年12月29日
VIP会员
相关VIP内容
【2020新书】实战R语言4,323页pdf
专知会员服务
100+阅读 · 2020年7月1日
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
161+阅读 · 2020年5月14日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
117+阅读 · 2020年5月10日
 第八届中国科技大学《计算机图形学》暑期课程课件
专知会员服务
55+阅读 · 2020年3月4日
【经典书】Python计算机视觉编程,中文版,363页pdf
专知会员服务
139+阅读 · 2020年2月16日
【阿里技术干货】知识结构化在阿里小蜜中的应用
专知会员服务
96+阅读 · 2019年12月14日
ExBert — 可视化分析Transformer学到的表示
专知会员服务
31+阅读 · 2019年10月16日
相关资讯
GitHub 热门:各大网站的 Python 爬虫登录汇总
机器学习算法与Python学习
9+阅读 · 2019年3月20日
抖音爬虫
专知
3+阅读 · 2019年2月11日
比Selenium快100倍的方法爬东方财富网财务报表
程序人生
8+阅读 · 2018年10月31日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
干货 | Python 爬虫的工具列表大全
机器学习算法与Python学习
10+阅读 · 2018年4月13日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
【python 自然语言处理】对胡歌【猎场】电视剧评论进行情感值分析
Python3爬虫之入门和正则表达式
全球人工智能
7+阅读 · 2017年10月9日
使用 Python 绘制《星战》词云
Datartisan数据工匠
3+阅读 · 2017年8月31日
33款可用来抓数据的开源爬虫软件工具 (推荐收藏)
数据科学浅谈
7+阅读 · 2017年7月29日
相关论文
Top
微信扫码咨询专知VIP会员