利用多线程+多进程以及代理池快速爬虫妹子图片

哎,太晚了,有空再写注释

Paste_Image.png

首先是队列文件mongodb_queue的代码,复制卧槽哥的

from datetime import datetime, timedelta
 +from pymongo import MongoClient, errors
 +
 +class MogoQueue():
 +
 +    OUTSTANDING = 1 ##初始状态
 +    PROCESSING = 2 ##正在下载状态
 +    COMPLETE = 3 ##下载完成状态
 +
 +    def __init__(self, db, collection, timeout=300):##初始mongodb连接
 +        self.client = MongoClient()
 +        self.Client = self.client[db]
 +        self.db = self.Client[collection]
 +        self.timeout = timeout
 +
 +    def __bool__(self):
 +        """
 +        这个函数,我的理解是如果下面的表达为真,则整个类为真
 +        至于有什么用,后面我会注明的(如果我的理解有误,请指点出来谢谢,我也是Python新手)
 +        $ne的意思是不匹配
 +        """
 +        record = self.db.find_one(
 +            {'status': {'$ne': self.COMPLETE}}
 +        )
 +        return True if record else False
 +
 +    def push(self, url, title): ##这个函数用来添加新的URL进队列
 +        try:
 +            self.db.insert({'_id': url, 'status': self.OUTSTANDING, '主题': title})
 +            print(url, '插入队列成功')
 +        except errors.DuplicateKeyError as e:  ##报错则代表已经存在于队列之中了
 +            print(url, '已经存在于队列中了')
 +            pass
 +    def push_imgurl(self, title, url):
 +        try:
 +            self.db.insert({'_id': title, 'statu': self.OUTSTANDING, 'url': url})
 +            print('图片地址插入成功')
 +        except errors.DuplicateKeyError as e:
 +            print('地址已经存在了')
 +            pass
 +
 +    def pop(self):
 +        """
 +        这个函数会查询队列中的所有状态为OUTSTANDING的值,
 +        更改状态,(query后面是查询)(update后面是更新)
 +        并返回_id(就是我们的URL),MongDB好使吧,^_^
 +        如果没有OUTSTANDING的值则调用repair()函数重置所有超时的状态为OUTSTANDING,
 +        $set是设置的意思,和MySQL的set语法一个意思
 +        """
 +        record = self.db.find_and_modify(
 +            query={'status': self.OUTSTANDING},
 +            update={'$set': {'status': self.PROCESSING, 'timestamp': datetime.now()}}
 +        )
 +        if record:
 +            return record['_id']
 +        else:
 +            self.repair()
 +            raise KeyError
 +
 +    def pop_title(self, url):
 +        record = self.db.find_one({'_id': url})
 +        return record['主题']
 +
 +    def peek(self):
 +        """这个函数是取出状态为 OUTSTANDING的文档并返回_id(URL)"""
 +        record = self.db.find_one({'status': self.OUTSTANDING})
 +        if record:
 +            return record['_id']
 +
 +    def complete(self, url):
 +        """这个函数是更新已完成的URL完成"""
 +        self.db.update({'_id': url}, {'$set': {'status': self.COMPLETE}})
 +
 +    def repair(self):
 +        """这个函数是重置状态$lt是比较"""
 +        record = self.db.find_and_modify(
 +           query={
 +               'timestamp': {'$lt': datetime.now() - timedelta(seconds=self.timeout)},
 +               'status': {'$ne': self.COMPLETE}
 +           },
 +            update={'$set': {'status': self.OUTSTANDING}}
 +        )
 +        if record:
            print('重置URL状态', record['_id'])
 

获取主题页面all_theme_urls的代码

from ip_request import html_request
from mongodb_queue import MogoQueue
from bs4 import BeautifulSoup



spider_queue = MogoQueue('meinvxiezhen','crawl_queue')
def start(url):
    response = html_request.get(url,3)
    soup = BeautifulSoup(response,'lxml')
    all_data = soup.find('div', {'class': 'all'}).findAll('a')
    for data in all_data:
        title = data.get_text()
        url = data ['href']
        spider_queue.push(url,title)
if __name__ == '__main__':
    start('http://www.mzitu.com/all')


这里是多线程多进程代码

import os
import time
import threading
import multiprocessing
from mongodb_queue import MogoQueue
from ip_request import html_request
from download import download_request
from bs4 import BeautifulSoup
sleep_time=2
def meizi_crawler(max_threads = 10):
    crawl_queue = MogoQueue('meinvxiezhen', 'crawl_queue')
    img_queue = MogoQueue('meinvxiezhen', 'img_queue')  ##这个是图片实际URL的队列
    def pageurl_crawler():
        while True:
            try :
                url=crawl_queue.pop()
                print(url)
            except KeyError:
                print('队列没有数据耶,你好坏耶')
            else:
                img_urls=[]
                title = crawl_queue.pop_title(url)
                path = str(title).replace('?', '')
                mkdir(path)
                os.chdir('C:\\Users\\admin\\Desktop\\mzitu\\{}'.format(path))
                req= html_request.get(url,3)
                max_page = BeautifulSoup(req, 'lxml').find('div', class_='pagenavi').find_all('span')[-2].get_text()
                for page in range(1, int(max_page) + 1):  # 找出每个套图里面最大的页数,这里真的不得不佩服我曹哥的想法

                    link = url + '/' + str(page)

                    data = html_request.get(link,3)

                    img_link = BeautifulSoup(data,'lxml').find('div', class_='main-image').find('img')['src']
                    img_urls.append(img_link)
                    download(img_link)
                crawl_queue.complete(url)
                img_queue.push_imgurl(title,img_urls)

    def download(url):#针对每个图片地址的下载函数
        f=open(url[-9:-4]+'.jpg','ab')
        #必须以二进制写进去
        f.write(download_request.get(url,3))
        f.close()
    def mkdir(path):#创建文件函数
        isExist = os.path.exists(os.path.join('C:\\Users\\admin\\Desktop\\mzitu',path))#检验这个目录下,path这个文件夹存在吗,
        #不存在就创建
        if not isExist:
            print('创建一个{}的文件'.format(path))
            os.makedirs(os.path.join('C:\\Users\\admin\\Desktop\\mzitu',path))
            return True
        else:
            print('文件{}已经存在'.format(path))
            return  False
    threads =[]
    while threads or crawl_queue:


#这儿crawl_queue用上了,就是我们__bool__函数的作用,为真则代表我们MongoDB队列里面还有数据
#threads 或者 crawl_queue为真都代表我们还没下载完成,程序就会继续执行

        for thread in threads:
            if not thread.is_alive():
                threads.remove(thread)
        while len(threads)< max_threads or crawl_queue.peek():
            thread = threading.Thread(target=pageurl_crawler())
            thread.setDaemon(True)
            thread.start()
            threads.append(thread)
        time.sleep(sleep_time)
def process_crawler():
    process=[]
    num_cpus=multiprocessing.cpu_count()
    print('将会启动的进程数为:',num_cpus)
    for i in range (num_cpus):
        p = multiprocessing.Process(target=meizi_crawler)
        p.start()
        process.append(p)  ##添加进进程队列
    for p in process:
        p.join()  ##等待进程队列里面的进程结束
if __name__ == '__main__':
    process_crawler()

15分钟爬了两百套左右,比单进程单线程快很多

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容