微信公众号:运维开发故事,作者:素心
这里将会以一个例子展开探讨多线程在爬虫中的应用,所以不会过多的解释理论性的东西,并发详情点击连接
爬取某应用商店
当然,爬取之前请自行诊断是否遵循君子协议,遵守就爬不了数据
查看robots协议只需要在域名后缀上即可
例如:
-
URL:
-
获取“游戏”分类的所有APP名称、简介、下载链接
2.1 网页属性
首先,需要判断是不是动态加载
点击翻页,发现URL后边加上了,这也就是说,查询参数为1的时候为第二页,写一个小爬虫测试一下
在输出的html中搜索“王者荣耀”,发现并没有什么问题,那么第二页呢?将上述代码中的改为
再次搜索第二页的内容”炉石传说”,发现并没有搜索出来,那么该网站可能是动态加载
-
抓包分析
打开chrome自带的窃听器,切换到network,点击翻页
可以看到该GET请求后缀很多参数
经过多次测试发现
-
为页数,但是值需要减1才是真实的页数
-
为应用分类
-
尚不明确,所以将抓到包的URL打开看一下
不难发现,为每一页显示APP信息的个数,并且返回了一个json字串
2.2 分析json
复制一段json过来
所有的信息都不知道是干啥的,暂时保存
2.3 二级页面
点击”王者荣耀”,跳转到APP详情,看下URL是什么样子
然后这里会惊奇的发现,id的查询参数和上边的的值一样,所以详情页就需要拼接URL
2.4 获取信息
-
APP名称
-
APP简介
-
APP下载地址
2.4 确认技术
由以上分析可以得出,使用lxml提取数据将会是不错的选择,有关xpath使用请点击跳转
xpath语法如下:
-
名称:
-
简介:
-
下载链接:
接下来将数据存储起来,存储的方式有很多csv、MySQL、MongoDB
这里采用MySQL数据库将其存入
建表SQL
简单介绍一下pymysql 的使用,该模块为第三方,需要用pip安装,安装方法不再赘述。
1.1 内置方法
pymysql方法
- 连接数据库,参数为连接信息(host, port, user, password, charset)
pymysql对象方法
-
游标,用来定位数据库
-
执行sql语句
-
提交事务
-
关闭游标
-
关闭连接
1.2 注意事项
只要涉及数据的修改操作,必须提交事务到数据库
查询数据库需要使用方法获取查询结果
1.3 详情
更多详情可以参考pymsql
创建配置文件(config.py)
表结构
SQL语句
完整代码
爬取上述信息似乎有点慢,如果数据多的话太耗时,而且计算机资源也得不到充分的利用
这就需要用多线程的理念,关于多进程和多线程的概念网上比比皆是,只需要明白一点
进程可以包含很多个线程,进程死掉,线程不复存在
打个比方,假设有一列火车,把这列火车理解成进程的话,那么每节车厢就是线程,正是这许许多多的线程才共同组成了进程
python中有多线程的概念
假设现在有两个运算:
在python内部实际上这样运算的
线程有一个特性,就是会争夺计算机资源,如果一个线程在刚刚计算了这时候另一个线程运行了,那么这样下来全就乱了, 也就是说n加上一千个1再减去一千个1结果不一定为1,这时就考虑线程加锁问题了。
每个线程在运行的时候争抢共享数据,如果线程A正在操作一块数据,这时B线程也要操作该数据,届时就有可能造成数据紊乱,从而影响整个程序的运行。
所以Python有一个机制,在一个线程工作的时候,它会把整个解释器锁掉,导致其他的线程无法访问任何资源,这把锁就叫做GIL全局解释器锁,正是因为有这把锁的存在,名义上的多线程实则变成了单线程,所以很多人称GIL是python鸡肋性的存在。
针对这一缺陷,很多的标准库和第三方模块或者库都是基于这种缺陷开发,进而使得Python在改进多线程这一块变得尤为困难,那么在实际的开发中,遇到这种问题本人目前用四种解决方式:
用代替
更换为
加同步锁
消息队列
如果需要全面性的了解并发,请点击并发编程,在这里只简单介绍使用
理解以上内容就可以将原来的代码改写多线程,改写之前加上来计时
多线程技术选用:
-
爬虫涉及IO操作较多,贸然改进程会造成计算机资源的浪费。
pass
-
更换简直没必要。
pass
-
加锁可以实现,不过针对IO还是比较慢,因为操作文件的话,必须加锁。
pass
-
使用消息队列可有效的提高爬虫速率。
线程池的设计:
- 既然爬取的页面有67页,APP多达2010个,则考虑将URL入列
下边是完整代码
当然这里的设计理念是将URL纳入队列之中,还可以将解析以及保存都写进线程,以提高程序的执行效率。
更多爬虫技术点击访问
欢迎各位一起交流