酷安是手机 App 爱好者的天堂,它有三点特别之处:可以搜索下载到各种其他应用下载市场几乎很难找到的应用;可以找到很多 App 的破解版;可以找到 Ap p的历史版本。此次就用 Scrapy 爬虫框架爬取该网 6000 多款 App,通过分析,希望找到不同领域下的精品 App。
目标总览
- 抓取网页数据
- 清理数据
- 对数据进行分析
一、抓取网页数据
抓取共计 6097 款 App,抓取了 8 个字段信息:App 名称、应用大小、下载量、关注人数、评分人数、App 分类标签、评分、评论数
- 这是我们要抓取的目标网页,点击翻页可以发现两点有用的信息:
- 每页显示 10 条 App 信息,一共 610 页,也就是有 6100 个左右的 App
-
网页请求是 GET 形式,URL 只有一个页数递增参数
主页面内显示了 App 名称、下载量、评分等信息,我们再点击 App 图标进入详情页,可以看到更齐全的信息,包括:应用大小、下载量、评分、分类标签等信息。


通过上述分析,我们就可以确定抓取流程了。首先遍历主页,抓取 10 个 App 的详情页 URL,然后到详情页抓取每个 App 数据,如此遍历下来,我们需要抓取 6000 多个网页内容,工作量不算小。所以,我尝试使用 Scrapy 框架进行抓取。
1、声明 item
首先,需要在 items.py 文件中,预先定义好要爬取的字段信息名称,如下所示:
class KuanItem(scrapy.Item):
# define the fields for your item here like:
name = scrapy.Field() # 名字
volume = scrapy.Field() # 文件大小
download = scrapy.Field() # 下载量
follow = scrapy.Field() # 关注量
comment = scrapy.Field() # 评论数
tags = scrapy.Field() # 标签
score = scrapy.Field() # 分数
num_score = scrapy.Field() # 评分人数
2、主程序
首先,我们需要在主页提取 App 的 URL 列表,然后再进入每个 App 的详情页进一步提取 8 个字段信息。利用 scrapy.Request() 方法构造每个 App 详情页的请求,这里我们传递两个参数: url 和 callback ,url 为详情页 URL ,callback 是回调函数,它将主页 URL 请求返回的响应 response 传给专门用来解析字段内容的 parse_url() 方法。这里还单独定义了 get_comment() 方法,通过正则表达式提取 volume 、download、follow、comment 四个字段信息。如下所示:
def parse(self, response):
a_list = response.xpath('//div[@class="app_left_list"]/a')
for a in a_list:
url = 'https://www.coolapk.com' + a.xpath('./@href').extract_first()
yield scrapy.Request(url, callback=self.parse_url)
def parse_url(self, response):
item = KuanItem()
item['name'] = response.xpath('//p[@class="detail_app_title"]/text()').extract_first()
resuslts = self.get_comment(response)
item['volume'] = resuslts[0]
item['download'] = resuslts[1]
item['follow'] = resuslts[2]
item['comment'] = resuslts[3]
item['tags'] = response.xpath('//span[@class="apk_left_span2"]/text()').extract()
item['score'] = response.xpath('//p[@class="rank_num"]/text()').extract_first()
num_score = response.xpath('//p[@class="apk_rank_p1"]/text()').extract_first()
item['num_score'] = re.search('共(.*?)个评分', num_score).group(1)
yield item
def get_comment(self, response):
messages = response.xpath('//p[@class="apk_topba_message"]/text()').extract_first()
result = re.findall(r'\s+(.*?)\s+/\s+(.*?)下载\s+/\s+(.*?)人关注\s+/\s+(.*?)个评论.*?', messages)
if result:
result = list(result[0])
return result
3、分页爬取
这里有两个方法去遍历全部 610 页的内容:
- 第一种是提取翻页的节点信息,然后构造出下一页的请求,然后重复调用 parse 方法进行解析,如此循环往复,直到解析完最后一页。
- 第二种是先直接构造出 610 页的 URL 地址,然后批量调用 parse 方法进行解析。
这里,我用第一种方法进行分页爬取,如下所示:
next_page = 'https://www.coolapk.com' + response.xpath('//ul[@class="pagination"]/li[8]/a/@href').extract_first()
yield scrapy.Request(next_page, callback=self.parse)
4、存储结果
我们在 pipelines.py 中,定义数据存储方法,这次我们用csv格式存储结果,如下所示:
def open_spider(self, spider):
with open('kuan.csv', 'a', encoding='utf-8') as csvfile:
fieldnames = ['name', 'volume', 'download', 'follow', 'comment', 'tags', 'score', 'num_score']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
def process_item(self, item, spider):
with open('kuan.csv', 'a', encoding='utf-8') as csvfile:
fieldnames = ['name', 'volume', 'download', 'follow', 'comment', 'tags', 'score', 'num_score']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writerow(item)
以上,就是整个数据的抓取过程。
网友评论