1. 页面分析

当我们在豌豆荚首页搜索框输入微信后,会跳转到搜索结果的页面,其url为http://www.wandoujia.com/search?key=%微信。搜索结果一般是按相关性排序的;所以,我们认为第一条搜索结果为所需要爬取的。紧接着,点进去后会跳转到页面http://www.wandoujia.com/apps/com.tencent.mm,我们会发现豌豆荚的APP的详情页,是www.wandoujia.com/apps/ + APP package组成。

让我们退回到搜索结果页面,分析页面元素,如图:

所有搜索结果在<ul>无序列表标签中,每一个搜索结果在<li>标签中。对应地,CSS选择器应为

'#j-search-list>li::attr(data-pn)'

接下来,我们来分析APP的详情页,APP的名称所对应的HTML元素如图:

APP类别的如图:

APP描述的如图:

不难得到这三类元素所对应的CSS选择器

.app-name>span::text.crumb>.second>a>span::text.desc-info>.con::text

通过上面的分析,确定爬取策略如下:

逐行读取APP文件,拼接搜索页面URL;

分析搜索结果页面,跳转到第一条结果对应的详情页;

爬取详情页相关结果,写到输出文件

2. 爬虫实现

分析完页面,可以coding写爬虫了。但是,若裸写Python实现,则要处理下载间隔、请求、页面解析、爬取结果序列化。Scrapy提供一个轻量级、快速的web爬虫框架,并很好地解决了这些问题;中文doc有比较详尽的介绍。

数据清洗

APP文件中,可能有一些名称不规整,需要做清洗:

URL处理

拿清洗后APP名称,拼接搜索结果页面URL。因为URL不识别中文等字符,需要用urllib.quote做URL编码:

爬取

Scrapy的爬虫均继承与scrapy.Spider类,主要的属性及方法:

name,爬虫的名称,scrapy crawl命令后可直接跟爬虫的名称,即可启动该爬虫

allowed_domains,允许爬取域名的列表

start_requests(),开始爬取的方法,返回一个可迭代对象(iterable),一般为scrapy.Request对象

parse(response),既可负责处理response并返回处理的数据,也可以跟进的URL(以做下一步处理)

items为保存爬取后数据的容器,类似于Python的dict,

豌豆荚Spider代码:

APP文件里的应用名作为搜索词,也应被写在输出文件里。但是,在爬取时URL有跳转,如何在不同层级间的Request传递变量呢?Request中的meta (dict) 参数实现了这种传递。

APP描述.desc-info>.con::text,extract返回的是一个list,拼接成string如下:

defparse_desc(desc):returnreduce(lambdaa, b: a.strip()+b.strip(), desc,'')

结果处理

Scrapy推荐的序列化方式为Json。Json的好处显而易见:

跨语言;

Schema明晰,较于'\t'分割的纯文本,读取不易出错

爬取结果有可能会有重复的、为空的(无搜索结果的);此外,Python2序列化Json时,对于中文字符,其编码为unicode。对于这些问题,可自定义Pipeline对结果进行处理:

还需在settings.py中设置

ITEM_PIPELINES = {'appMarket.pipelines.CheckPipeline':300,'appMarket.pipelines.JsonWriterPipeline':800,}

分配给每个类的整型值,确定了他们运行的顺序,按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内。


本文转载:CSDN博客