有了列表,有了返回格式,接下来就是要把这些信息给扒下来,其实就是重复遍历一遍就可以了,要么用著名 Python 的 Requests库 循环一圈,要么使用 Python 的爬虫框架 Scrapy, 都是可以的,本次决定使用 Scrapy。在存储爬取数据存储方面,本来打算是存入 mongodb 的,但是遇到的一个坑是API返回的json对象里version有的key是带小数点的,比如"0.1"这种是无法直接存入mongodb的,会报错说key不能包括., 所以这可以祭出另外一个厉害的python库 jsonline了, 它可以以jsonl文件的形式一行存储一条json,读写速度也很快。最后爬完所有数据的这个文件有341M之大。。。

最后,有了数据就可以做一些有意思的数据分析了,这一步主要会用到的就是一些常见的 Python 的数据分析工具和图表工具,pandas、numpy、seaborn等。根据上面的返回信息可以看出,能够分析的维度也是很多的,比如哪些作者开发的插件最多、哪些插件的下载量最多、哪些类别的插件最多、哪些国家的开发者最多、每年的插件增长量等等,甚至更进一步可以把所有插件的zip文件下载下来用AI做一些深入的代码分析等等,想想还是挺有意思的,本文的目标也就是提供一种思路和方法,希望能抛砖引玉。

下面进开始进入代码的世界吧

爬取数据

准备工作

要爬数据一般第一步是要确认爬虫的入口网页,也就是从哪里开始爬,沿着入口网页找到下一个URL,找-爬-找,不断循环重复直到结束。一般来说入口网页的分析都可以在scrapy内部进行处理,如果事先就已经可以明确知道所有要请求的网页地址,那么也可以直接把url列表扔进scrpay里,让它顺着列表一直爬爬爬就行了。

本次为了说的清晰一点,爬虫部分不用再次解释,所以分步进行,先把要爬的所有url准备好等下可以直接使用。之前说过了,WordPress所有的插件名称列表在这里可以找到 http://plugins.svn.wordpress.org/ ,这网页是一个非常简单的静态网页,就是一个巨大的ul列表,每一个li就是一个插件名字:

<ul>
  <li><a href="0-delay-late-caching-for-feeds/">0-delay-late-caching-for-feeds/</a></li>
  <li><a href="0-errors/">0-errors/</a></li>
  <li><a href="001-prime-strategy-translate-accelerator/">001-prime-strategy-translate-accelerator/</a></li>
  <li><a href="002-ps-custom-post-type/">002-ps-custom-post-type/</a></li>
  <li><a href="011-ps-custom-taxonomy/">011-ps-custom-taxonomy/</a></li>
  <li><a href="012-ps-multi-languages/">012-ps-multi-languages/</a></li>

这里的href就是插件的slug,是wordpress.org用来确定插件的唯一标示。解析这种html对Python来说简直是小菜一碟,比如最常用的 BeautifulSoup 或者 lxmp,这次决定尝试一个比较新的库,Requests-HTML: HTML Parsing for Humans ,这也是开发出Requests库的大神kennethreitz的又一力作,用于解析 HTML 文档的简直不要太爽了。

slug得到后,按照API的url格式地址组合起来,全部写入一个文件中就可以了。

from requests_html import HTMLSession

session = HTMLSession()

r = session.get('http://plugins.svn.wordpress.org/')

links = r.html.links  

slugs=[ link.replace('/','') for link in links ]

plugins_urls=[ "https://api.wordpress.org/plugins/info/1.0/{}.json".format(slug) for slug in slugs ]

with open('all_plugins_urls.txt','a') as out:
    out.write("\n".join(plugins_urls))

作为对比,可以看下用 BeautifulSoup 的方法:

import requests 
from bs4 import BeautifulSoup

html=requests.get("http://plugins.svn.wordpress.org/").text

soup=BeautifulSoup(html,features="lxml")
lis=soup.find_all('li')
baseurl="https://api.wordpress.org/plugins/info/1.0/"

with open('all_plugins_urls.txt','a') as out:
    for a in soup.find_all('a', href=True):
        out.write(  baseurl + a['href'].replace('/','') + ".json"+"\n")

就这么一个简单对比还是比较明显的,简单明了。最终,这一步的输出结果就是这个all_plugins_urls.txt文件了,总共有79223个插件。

有了这个列表,其实下面的Scrapy步骤其实完全可以不用,直接拿wget都可以全部简单粗暴的怼下来7万个json文件:

wget -i all_plugins_urls.txt

或者用requests简单的遍历请求一下就完事了,就可以得到所有插件的数据,进而可以直接进入数据分析阶段了。为了作为演示吧,也算作是一个简单的scrapy的介绍,对于没有接触过scrapy的朋友来说,可以是一个很初步的入门介绍。

安装 scrapy

这一步最简单的方式就是pip安装

pip install Scrapy
scarpy -V # 验证一下
新建项目 (Project):新建一个新的爬虫项目

scrapy 提供了完善的命令工具可以方便的进行各种爬虫相关的操作。一般来说,使用 scrapy 的第一件事就是创建你的Scrapy项目。我的习惯是首先新建一个文件夹(用要爬的网站来命名,这样可以方便的区分不同网站的爬虫项目)作为总的工作区, 然后进入这个文件夹里新建一个 scrapy 的项目,项目的名字叫做 scrap_wp_plugins,可以改成你想要的名字

mkdir ~/workplace/wordpress.org-spider
cd ~/workplace/wordpress.org-spider
scrapy startproject  scrap_wp_plugins

这样就会自动创建好类似如下的文件结构:

├── scrap_wp_plugins
│   ├── __init__.py
│   ├── __pycache__
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
│       └── __pycache__
└── scrapy.cfg

4 directories, 7 files

对我们这个需求来说,除了settings.py需要做一点点修改,其余文件都先不用管它,在这个简单的不能再简单的项目里都用不到。

目前只是一个空架子,啥也干不了,因为还没有爬虫文件,你可以完全纯手写,也可以用模板来生成一个。我们就用scrapy的命令行自动生成一个爬虫,语法格式是这样:

Syntax: scrapy genspider [-t template] <name> <domain>

template 是要使用的爬虫的模板,默认的就是用最基本的一个。

name 就是爬虫的名字,这个可以随便取,等下要开始爬的时候会用到这个名字。好比给你的小蜘蛛取名叫“春十三”,那么在召唤它的时候你就可以大喊一声:“上吧!我的春十三!”

domain 是爬虫运行时允许的域名,好比说:“上吧!我的春十三!只沿着这条路线上!”

所以执行如下命令即可:

cd scrap_wp_plugins
scrapy genspider plugins_spider wordpress.org

这样就会在spiders文件夹下生出一个叫plugins_spider.py的爬虫文件,也就是在这里面可以填充一些爬取逻辑和内容解析。

制作爬虫(Spider):制作爬虫开始爬取网页

首先我们打开scrap_wp_plugins/plugins_spider.py看下里面的内容:

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


**(1)Python所有方向的学习路线(新版)**  

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。