爬虫【9】 小米应用商店爬虫(多线程)

爬虫【9】 小米应用商店爬虫(多线程)


爬虫回顾:


多线程介绍

应用场景

1、多进程 :CPU密集程序
2、多线程 :爬虫(网络I/O)、本地磁盘I/O

队列

# 导入模块
from queue import Queue
# 使用
q = Queue()
q.put(url)
q.get() # 当队列为空时,阻塞
q.empty() # 判断队列是否为空,True/False

线程模块

# 导入模块
from threading import Thread

# 使用流程  
t = Thread(target=函数名) # 创建线程对象
t.start() # 创建并启动线程
t.join()  # 阻塞等待回收线程

爬虫小米应用商店

爬取目标:爬取旁栏中的地址,并且同时爬取地址中对应的app名称以及每个app对应的url链接:
在这里插入图片描述

想爬取旁中的url地址

步骤:
右键打开网页源代码,搜索需要的内容
发现是静态页面
使用xpath匹配去匹配需要的内容

在这里插入图片描述
静态的url界面还是非常简单的,可以看到url地址和名称

应用名称://ul[@class="category-list"]/li/a/text()
对应url: //ul[@class="category-list"]/li/a/@href  (这里并不是完整的url,但是问题不大后面讲怎么用)

爬虫对应专栏的app名称

1. 确认是否为动态加载
1、页面局部刷新
2、右键查看网页源代码,搜索关键字未搜到
   ==>  此网站为动态加载网站,需要抓取网络数据包分析
2. F12抓取网络数据包

什么按一下页面的按钮,就抓到一个包,获取方式为get,检查条件有page,categoryld pageSize
在这里插入图片描述
到他请求的地址去看一看
http://app.mi.com/categotyAllListApi?page=1&categoryId=27&pageSize=30
发现是对应的json数据
在这里插入图片描述
接下来我们分析一下他的url
在这里插入图片描述

获取页数

知道url的类型后我们就知道怎么办了,类别在上面已经获取过了还记得吗?关键这个page怎么获得啊?

观察上面的json数据,我可以看到有一个count的参数,这个参数应该就是这个类别的总的app个数
max_page = count // 30 + 1
这样我们就获得页数啦
思路分析图:

在这里插入图片描述
明白思路后就可以去敲代码了

代码

大晚上的小米应用商店应该也没啥人,我就每怎么啥time.sleep, 快点爬完我要去sleep了

import time
import requests
import csv
from queue import  Queue
from multiprocessing import Process,Lock
from fake_useragent import UserAgent
from lxml import etree

class XiaoMiSpider:
    def __init__(self):
        self.q = Queue()
        self.url = 'http://app.mi.com/categotyAllListApi?page={}&categoryId={}&pageSize=30'
        # 创建url队列,存放所有待爬取的URL地址
        self.q = Queue()
        # 创建csv文件对象
        self.f = open('xiaomi.csv','a')
        self.lock = Lock()
        self.writer = csv.writer(self.f)
        # 计数
        self.i = 1

    def get_all_type(self):
        """
        获取所有的类别信息
        """
        url = 'http://app.mi.com/'
        html = requests.get(url=url,headers=self.get_headers()).text
        html = etree.HTML(html)
        categorylds = html.xpath('//ul[@class="category-list"]/li/a/@href')
        for categoryld in categorylds:
            categoryld = categoryld.split('/')[-1]
            self.url_in(categoryld)

    def url_in(self,categoryld):
        """
        将url推送到队列当中
        """
        total = self.get_total(categoryld)
        for page in range(total):
            url = self.get_url(page,categoryld)
            print(url)
            self.q.put(url)


    def get_url(self,page,categoryId):
        url = self.url.format(page,categoryId)
        return url

    def get_total(self,categoryId):
        """
        获取文章的总数
        """
        url = self.url.format(0,categoryId)
        html = requests.get(url=url,headers=self.get_headers()).json()
        count = html['count']
        if count % 30 == 0:
            total = count // 30
        else:
            total = (count // 30) + 1
        return total

    def get_headers(self):
        """
        获取请求头
        """
        ua = UserAgent()
        headers = {'User-Agent':ua.random}
        return headers

    def parse_html(self):
        """
        解析html,并写入csv文件
        """
        while True:
            if not self.q.empty():
                url = self.q.get()
                html = requests.get(url,self.get_headers()).json()
                app_list = []
                for app in html['data']:
                    name = app['displayName']
                    print(name)
                    icon = app['icon']
                    app_list.append((name,icon))
                    self.lock.acquire()
                    self.i += 1
                    self.lock.release()
                # 加锁+释放锁
                self.lock.acquire()
                self.writer.writerows(app_list)
                self.lock.release()
                time.sleep(0.1)
            else:
                break



    def run(self):
        """
        多线程路口
        """
        self.get_all_type()
        t_list = []
        for i in range(10):
            t = Process(target=self.parse_html)
            t_list.append(t)
            t.start()
        for j in t_list:
            j.join()

if __name__ == '__main__':
    aaa = XiaoMiSpider()
    aaa.run()
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值