python爬虫的最佳实践(六)--爬虫中的多进程

ps:写给新手看的,大神看到了轻喷,给我留点面子~

写在前面

为什么选用多进程而不选用多线程,这是考虑到了诸多的实际情况最终做出的选择。

  • 在python环境下,多进程稍稍比多线程好实现好理解一点。
  • 因为爬虫大多数都是运行在linux内核的服务器上面,而在linux操作系统下,多进程要比多线程更加合适,因为调度开销和多线程差不多,但是进程性能更好。如果在windows系统下跑爬虫的话,建议使用框架或者使用多线程。
  • 爬虫毕竟不是服务器交互,没有人会开1k的线程去跑这个,所以一般情况下我们把自己爬虫的效率提升几倍即可。

有兴趣的同学可以去看一下进程和线程的区别,据说面试容易被问喔我们今天就讲一下简单的多进程的实现就好了,如果你想深入爬虫效率研究可以好好研究一下多进程和多线程相关

代码预览

#coding:utf-8
import multiprocessing
from bs4 import BeautifulSoup
import requests

def pageUrls(url):
    web_data = requests.get(url)
    soup = BeautifulSoup(web_data.text, 'lxml')
    sum = int(soup.select('span.total > em:nth-of-type(1)')[0].get_text())
    pageNum = sum/50
    return [url+'/loupan/s?p={}'.format(str(i)) for i in range(1, pageNum+2, 1)]

def detailPage(myurl):
    urls = pageUrls(myurl)
    for url in urls:
        web_data = requests.get(url)
        soup = BeautifulSoup(web_data.text, 'lxml')
        titles = soup.select('div.list-results > div.key-list > div > div.infos > div > h3 > a')
        for title in titles:
            print url
            print title.get_text()
            print title.get('href')

def main(urls):
    pool = multiprocessing.Pool(multiprocessing.cpu_count())
    for url in urls:
        pool.apply_async(detailPage, (url, ))
    # pool.map(detailPage, urls)
    pool.close()
    pool.join()


if __name__ == "__main__":
    startUrl = 'http://tj.fang.anjuke.com/?from=navigation'
    web_data = requests.get(startUrl)
    soup = BeautifulSoup(web_data.text, 'lxml')
    urls = [url.get('href') for url in soup.select('.city-mod > dl > dd > a')]
    main(urls)

代码剖析

if __name__ == "__main__":
    startUrl = 'http://tj.fang.anjuke.com/?from=navigation'
    web_data = requests.get(startUrl)
    soup = BeautifulSoup(web_data.text, 'lxml')
    urls = [url.get('href') for url in soup.select('.city-mod > dl > dd > a')]
    main(urls)

在这里讲一个小知识点,if __name__ == "__main__":这段代码的作用是保证在这个py文件被import的时候不会被运行,只有主动执行它的时候才会运行。
这次我们扒取的是安居客的住房信息,上面那一段代码相信大家都能看懂,从入口进入,取到全国各地城市的链接,然后进入main函数

pool = multiprocessing.Pool(multiprocessing.cpu_count())
multiprocessing是python中标准的多进程库,上面代码的意思是创建一个进程池,进程个数为cpu内核数。这里有个小知识,电脑的cpu有多少内核便可以同时执行多少个进程,当然你也可以填的很多,只是作用不大而已,并不是进程数越多就会执行的越快。

pool.apply_async(detailPage, (url, ))
apply_async函数从进程池中取出一个进程执行func,args为func的参数,我们这段代码不断地从进程池中取出进程去执行我们的detailPage方法。当然,也可以采用下面哪种方式:
pool.map(detailPage, urls)
map方法,将detailPage()函数作用到表的每个元素上,表中每个元素都会被作用到。这两种方式都可以~

pool.close()关闭进程池,进程池不会再创建新的进程
pool.join()wait进程池中的全部进程,也就是用来等待进程池中的worker进程执行完毕,防止主进程在worker进程结束前结束

这样,对于我的电脑来说等于开了8个进程去并行爬虫(没做反扒一会就会被封了哈哈),经过我测试速度比单个进程快了4倍左右,还是很有用的~

剩下的两个函数我就不多赘述了pageUrls,根据页面上数据量的多少生成page分页的url,detailPage扒取每个page分页的所有楼盘的标题信息。

今天我们介绍了多进程,同时,实践了如何从网站的一个入口延伸进而抓取整个网站的内容。当然,每个人写代码的习惯不同,当你多多练习的时候自然有自己的方式去实现你想要的功能。

ps:今天突然想起来,大家在做爬虫的时候尽量先扒到链接,存在数据库之后再去扒分页里面的详细内容,因为这样速度不慢而且容错率很高,也很容易做断点续扒~

写在最后

经过前面几章的学习,我相信你已经可以扒取大部分网站了,并且有不错的效率。下一章我们将学习py爬虫的框架pyspider我觉得还是很好用的

有兴趣的同学可以加群498945822一起交流学习哦~~
发现问题的同学欢迎指正,直接说就行,不用留面子,博主脸皮厚!

推荐阅读更多精彩内容

  • 1 前言 作为一名合格的数据分析师,其完整的技术知识体系必须贯穿数据获取、数据存储、数据提取、数据分析、数据挖掘、...
    whenif阅读 17,202评论 45 524
  • @(python)[笔记] 目录 一、什么是进程 1.1 进程的概念 进程的概念起源于操作系统,是操作系统最核心的...
    CaiGuangyin阅读 1,014评论 0 9
  • 怎样让python在现代的机器上运行的更快,充分利用多个核心,有效地实现并行、并发一直是人们的追求方向。 GIL ...
    treelake阅读 7,203评论 2 76
  • 进程与线程的区别 现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码...
    苏糊阅读 612评论 0 2
  • 概述 android上原生的弹出框和ios原生的弹出框视觉差距较大,为了与ios的视觉效果类似,所以封装了这个库。...
    追梦3000阅读 2,176评论 1 1
  • 在人们的印象里,师范专业毕业的学生就应该在学校里当老师,2013年从福师大毕业的何杰却怀揣着一个创业梦想。...
    陈燕双阅读 193评论 0 1
  • 文/芦苇上的虫 凌晨四点,我为妈妈打卡,不是学习打卡,也不是所谓的早起打卡,而是睡觉打卡! 凌晨四点,当大地都仿佛...
    芦苇上的虫阅读 258评论 0 3
  • 创立动机:以社区为依托,以社区共享空间为载体,以全职妈妈们丰富的育儿经验为基石,以读书会为共融的方式,同时积极链接...
    王五月阅读 856评论 0 1