练习利用Scrapy爬取b站排行榜

开始学 python 的 Scrapy 框架了,参考书是崔庆才的《python3 网络爬虫开发实战》

跟着示例敲完之后,又试着按照一样的逻辑去爬取了 B 站排行榜的数据。

通过这个小项目学习使用 Scrapy 框架。

步骤

新建项目

首先新建一个名为practice的项目

1
$scrapy startproject practice

这个项目的目录结构(省略 init 文件):

  • practice
    • practice
      • items.py
      • middlewares.py
      • pipelines.py
      • settings.py
    • scrapy.cfg

这一个项目里面的代码是整个项目的爬虫通用的。

新建 Spider

新建一个爬虫bilibiliRank

1
2
$cd practice
$scrapy genspider bilibiliRank

然后与在此目录下出现了一个spider文件夹,用于存放这个新的爬虫

  • spider
    • bilibiliRank.py

bilibiliRank.py中:

1
2
3
4
5
6
7
8
9
import scrapy

class BilibilirankSpider(scrapy.Spider):
name = 'bilibiliRank'#爬虫名字
allowed_domains = ['bilibili.com']#允许爬取的域名
start_urls = ['https://www.bilibili.com/ranking/']#初始url

def parse(self, response):
pass

spider文件夹里面是用于爬取不同网站的爬虫,它继承自scrapy.Spider,scrapy 的引擎Engine就是利用你写的爬虫里面的parse()方法来解析页面获取数据,可以在这个方法里面将数据以item的形式返回出去,给ItemPipeline继续处理。

创建 Item

items.py里面定义了不同的 item,这些 item 都继承自scrapy.Item,文件生成的内容如下(无关注释已删去):

1
2
3
4
5
6
import scrapy

class PracticeItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
pass

在这里你可以照着它的模板新建一个类,也可以直接修改,总之只要符合要求就可以:

1
2
3
4
5
6
7
8
import scrapy

class RankItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
num=scrapy.Field()
title=scrapy.Field()

在这个 Item 子类当中,我新建了两个域,也可以说是字段。按照注释给出的格式来就可以了。

解析 response

适当简化的流程大概是:引擎利用爬虫的start_url发起请求,然后将得到的响应response作为参数传入爬虫的parse()方法中。parse()将解析出的数据装入Item并返回给引擎。

需要解析的 html 页面内容(只展示其中一个项的结构):

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
<ul class="rank-list">
<li class="rank-item">
<div class="num">1</div>
<div class="content">
<div class="img">
<a href="//www.bilibili.com/video/av56121331/" target="_blank">
<div class="lazy-img cover">
<img alt="视频标题" src="图片url" />
</div>
</a>
<div class="watch-later-trigger w-later"></div>
</div>
<div class="info">
<a href="视频url" target="_blank" class="title">视频标题</a
><!---->
<div class="detail">
<span class="data-box"> <i class="b-icon play"></i>366.8万</span>
<span class="data-box"><i class="b-icon view"></i>3.8万</span>
<a target="_blank" href="视频url">
<span class="data-box">
<i class="b-icon author"></i>作者名</span
></a
>
</div>
<div class="pts">
<div>3798978</div>
综合得分
</div>
</div>
<!---->
</div>
</li>
</ul>

爬虫文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import scrapy
from practice.items import RankItem#这是之前自定义的item

class BilibilirankSpider(scrapy.Spider):
name = 'bilibiliRank'
allowed_domains = ['bilibili.com']
start_urls = ['https://www.bilibili.com/ranking/']

def parse(self, response):
#获取所有的项目
rank_items=response.css('.rank-list .rank-item')
#获取每一项中的数据
for rank_item in rank_items:
item=RankItem()
item['num']=rank_item.css('.num::text').extract_first()
item['title']=rank_item.css('.content .info .title::text').extract_first()
yield item#每次调用就会返回一个item

遇到的问题:

  1. 注意获取的所有项目得是一个节点,不能用extract()读取其中的数据,第一次写时,写成了:
1
2
3
rank_list=response.css('.rank-item').extract()
for rank_item in rank_list:
#……

爬取

1
$scrapy crawl bilibiliRank -o bilibiliRank.json

利用名为bilibiliRank爬虫进行爬取,并将得到的结果保存在bilibiliRank.json文件中

参考链接

作者

憧憬少

发布于

2019-06-25

更新于

2019-06-25

许可协议