logo头像
Snippet 博客主题

使用Pyspider爬虫网站数据

环境搭建

pyspider 介绍

pyspider 是一个基于Python语言的功能强大的爬虫框架,支持在浏览器界面进行代码调试,对爬取状态、进度和结果实时查看,支持多线程工作。更多请查看官方文档

系统环境

  • Windows 10
  • Python 3.6

安装

首先搭建环境,注意pyspider与python3.7 因为关键字冲突而不兼容,需要进行繁琐的配置。因此,我使用了Python 3.6。安装pyspider:

1
pip install pyspider

但是 报错缺少依赖包 pycurl。
到网站https://www.lfd.uci.edu/~gohlke/pythonlibs/找到pycurl,下载自己对应的版本
如何下载自己所对应的的第三方依赖包的版本?
在cmd中输入pyhton:

1
2
Python 3.6.8 |Anaconda, Inc.| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

由此可知,我的Python 为3.6.8 64bit (AMD64)。
所以下载的pycurl 为:

1
[pycurl‑7.43.0.3‑cp36‑cp36m‑win_amd64.whl](javascript:; "[3.1 MB] [Jun 23, 2019]")

其中:

  • cp36: Pyhton 3.6
  • amd64: 64位

另外,如果爬取的页面中,有带JS的页面,则需要安装 PlantomJS ,安装教程如下:
点击https://phantomjs.org/download.html,下载Windows版本,然后解压缩出来后,将\bin 目录下的 phantomjs.exe 文件放到 Python.exe 的同级目录下即可。

配置好环境后,运行Pyspider:

1
pypider all

run
可以看到phantomjs 已经运行, pyspider运行在 http://127.0.0.1:5000/ 端口,下为pyspider dashboard界面。
界面
至此,环境已经配置成功。注意CMD窗口不要关闭,否则端口将失效。

爬虫实例

需求:以 https://www.luoow.com/ 为例,爬取该网站的999个歌单的数据信息(歌单名称,歌曲数目,歌单介绍,歌单封面链接,歌单中每个歌曲的名称及歌手名称),并以json格式保存在txt文本文件中。

落网

新建任务

新建任务

  • Project Name: 项目的名称,自己可以随意填写。
  • Start URL(s): 项目爬取的目标网址。

下为系统自动生成的初始化界面:
初始化界面

代码编写与调试

代码的编写需要用到CSS选择器的知识,在目标网页右键检查
网页源码
有几种常用的格式:

  • 获取这行所指的文本 比如 vol.5 A New Begining
    text

    1
    2
    3
    response.doc('div[class="title"]').text()  #input[id = “code”]  id属性为code的input标签。.text()表示返回文本。
    或者
    response.doc('div.title').text() #是上文的简写形式,表示class为title的div标签
  • 获取这个图片的网址:
    src

    1
    picture = response.doc('img.img-responsive').attr.src #attr.src 表示属性中src的值。

以下为我最终写的爬取落网歌单的Python代码:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python
#-*- encoding: utf-8 -*-
#Created on 2020-01-09 10:17:30
#Project: 999

from pyspider.libs.base_handler import *
import json

class Handler(BaseHandler):
def __init__(self):
self.base_url = 'http://www.luoow.com/'
self.start = 1
self.end = 999
crawl_config = {
}
@every(minutes=24 * 60)
def on_start(self):
self.crawl('http://www.luoow.com/', callback=self.index_page)
@config(age=10 * 24 * 60 * 60)
def index_page(self, response):
while self.start <= self.end:
url = self.base_url + str(self.start)
print(url)
self.crawl(url, callback=self.detail_page, fetch_type= 'js') #fetch_type= 'js' 表示打开有JS渲染的界面,本示例中的歌单均有JS,否则抓取不成功。
self.start += 1

@config(priority=2)
def detail_page(self, response):
songer_name= []
song_name = []
picture = response.doc('img.img-responsive').attr.src

for each in response.doc('span[class = "skPlayer-list-author"]').items(): #class 里面不能有空格
songer_name.append(each.text())

for each in response.doc('span[class = "skPlayer-list-name"]').items():
song_name.append(each.text()[4:])

song_count = len(song_name)

all_song = []
for i in range(song_count):
current_song = {
"song_name" : song_name[i],
"songer_name" : songer_name[i]
}
all_song.append(current_song)

all = {
"name": response.doc('div.title').text(),
"song_count": song_count,
"introduction" : response.doc('div[class = "vol-desc"]').text(),
"img_url" : picture,
"songs" : all_song
}
with open(r"E:\project\python\spider\999.txt", "a",encoding='utf-8') as f: # 1. 一定要说明 utf-8 编码,否则会报错,无法正常显示非英文字符。 2. 读取方式为 "a" 表示为 不覆盖文件中。
f.write(json.dumps(all,ensure_ascii = False)) #ensure_ascii = False 在txt 中,使得中文可以正常显示
f.write(',') #在每个歌单之间加上 ‘,’号,以符合json格式。


return { #return 的数据会返回到dashboard的results中
"name": response.doc('div.title').text(),
"song_count": song_count,
"introduction" : response.doc('div[class = "vol-desc"]').text(),
"img_url" : picture,
"songs" : all_song
}

pyspider 支持在线调试并实时查看爬虫结果。
debug

debug
调试无误后,返回 pyspider dashboard 界面。

运行

调试完成后,将该项目的CHECKING 改为 RUNNING,并点击Run,pyspider 就开始爬虫工作了。
debug
运行后Results中开始刷新数据,并且CMD窗口中也一直在显示爬取结果。

各参数的含义为:

  • rate/burst 代表当前的爬取速率。rate 代表 1 秒发出多少个请求,burst 相当于流量控制中的令牌桶算法的令牌数,rate 和 burst 设置的越大,爬取速率越快,当然速率需要考虑本机性能和爬取过快被封的问题。

  • process 中的 5m、1h、1d 指 的是最近 5 分、1 小时、1 天内的请求情况,all 代表所有的请求情况。

  • 颜色请求由不同颜色表示、蓝色的代表等待被执行的请求,绿色的代表成功的请求,黄色的代表请求失败后等待重试的请求,红色的代表失败次数过多而被忽略的请求,这样可以直观知道爬取的进度和请求情况。

  • Run 爬虫运行的按钮。

  • Active Tasks 可以看到任务进行的状态,比如爬到哪个网址了,以及是否爬取成功等。
  • Results 爬虫结果。

爬虫结果

  • 点击Results后查看,已经成功得到了所需要的信息。可以点击右上角进行保存。
    Results

  • txt文件。由于我的需求是将爬取结果以json格式保存为txt,故我在源码中使用write方法将爬虫结果保存下来:

    1
    2
    3
    with open(r"E:\project\python\spider\999.txt", "a",encoding='utf-8') as f: # 1. 一定要说明 utf-8 编码,否则会报错,无法正常显示非英文字符。 2. 读取方式为 "a" 表示为 不覆盖文件中。
    f.write(json.dumps(all,ensure_ascii = False)) #ensure_ascii = False 在txt 中,使得中文可以正常显示
    f.write(',') #在每个歌单之间加上 ‘,’号,以符合json格式。

Results
:为了符合json格式要求,[{…},{…},{…}]
需要手动修改,删除掉txt文件末尾的最后一个“,”,并在首尾处分别加上“[” “]”。

格式校验

打开在线JSON校验格式化工具(Be JSON)
复制txt文件中的内容到该网站,点击格式化校验,可以看到所得到的json为正确格式。
Results

至此,已经成功爬取到了落网所有歌单的数据,并以正确的json格式保存在txt文件中。由于,此次不涉及数据库和反爬机制,暂不做赘述。

附录

代码源码:点击下载源码

csv: 点击下载CSV文件
注:关于CSV乱码问题的解决方案:
单击该CSV文件,右键以记事本方式打开,另存为的时候将编码方式改为ANSI,再次打开显示正常。
Results

参考文献

[1] pyspider的使用
[2] CSS 选择器参考手册
[3] pyspider 爬虫教程(三):使用 PhantomJS 渲染带 JS 的页面