精华内容
下载资源
问答
  • python多线程爬虫

    2019-11-25 12:30:30
    python多线程爬虫 python单线程爬虫对于应付小规模数据是可以的,但是面对大量数据,我们就要用到多线程爬虫技术。使用多线程,一方面可能会加快效率,另一方面可以施加一些小技巧,如不同的线程使用不同的代理ip...

    python多线程爬虫

    python单线程爬虫对于应付小规模数据是可以的,但是面对大量数据,我们就要用到多线程爬虫技术。使用多线程,一方面可能会加快效率,另一方面可以施加一些小技巧,如不同的线程使用不同的代理ip从而避免出发反爬机制。

    python 多线程

    python的多线程可以用thread类来实现,具体实现的代码很简单,直接贴上就行了。
    python线程还有一些标准库函数,如 threading.current_thread() 返回当前线程信息,具体使用时候可以查文档。

    def thread_job():
        #线程要做的事情
    
    # 开启10个线程
    for i in range(10):
        # thread_job是线程要调用的函数,后面也可以带参数
        t = threading.Thread(target=thread_job)
        t.start()
    
    python多线程是不是一定更有效率

    python多线程只是有可能更有效率。
    python中有GIL(Global Interpreter Lock),这个是全局锁,历史遗留问题。这个东西保证了同一时刻只有一个线程在一个CPU上执行字节码,无法将多个线程映射到多个CPU上,也就是说python的多线程是伪多线程。并且线程之间的切换是有损耗的。
    那么python为什么又要引入多线程呢?虽然同一时间内只能有一个线程在一个cpu上执行字节码,但是可以有多个线程去做I/O操作。在单线程中处理I/O操作是比较费时的,所以在I/O操作比较多的时候,选用多线程爬虫是有可能进效率的;而需要cpu计算较多的时候,选用单线程更合适。

    线程共享变量,锁

    多个线程运行时,免不了要访问共有的全局变量,容易导致全局变量的混乱。那么为了解决这个问题,引入了锁。对代码块加上锁之后,就只有当前线程独占这些资源,其他是不能访问的,除非锁释放了。
    如:

    lock.acquire()
    url = q.get()
    lock.release()
    
    多线程爬虫

    多线程爬虫顾名思义,实际上也就是在爬虫的基础上增加一个多线程。最关键的问题就是url的调度问题。url则可以用一个队列Queue来存储,多个线程在访问Queue时候使用锁就行了。

    import threading
    from queue import Queue
    import requests
    from bs4 import BeautifulSoup
    
    BASE_URL = 'https://movie.douban.com/people/71745673/collect?start={start}&sort=time&rating=all&filter=all&mode=grid'
    
    HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5'
    }
    
    def thread_job():
        global q, lock
        while not q.empty():
            lock.acquire()
            url = q.get()
            lock.release()
            soup = BeautifulSoup(requests.get(url=url, headers=HEADERS).text, 'lxml')
            items = soup.find_all('div', attrs={'class': 'item'})
            for item in items:
                movieItem = {}
                movieItem['title'] = item.find('em').text
                movieItem['date'] = item.find('span', attrs={'class': 'date'}).text
                print(threading.current_thread(), movieItem)
    
    if __name__ == '__main__':
        q = Queue()
        lock = threading.Lock()
        # 总共65页
        for page in range(0, 65):
            url = BASE_URL.format(start=page*15)
            q.put(url)
        for i in range(10):
            t = threading.Thread(target=thread_job)
            t.start()
    
    展开全文
  • Python多线程爬虫

    2016-11-07 14:21:14
    Python多线程爬虫 功能描述 使用python编写一个网站爬虫程序,支持参数如下: spider.py -u url -d deep -f logfile -l loglevel(1-5) --testself -thread number --dbfile filepath --key=”HTML5” 参数说明: -...
  • Python 多线程爬虫

    千次阅读 2020-10-24 13:53:30
    实现多线程爬虫 为什么要爬虫使用多线程? 为了提高抓取数据效率 有些网站对访问速度有限制, 这样网站可以可以开启多个线程, 每一个线程使用一个代理,去提取页面的一部分内容 1.多线程的方法使用 在python3中,...

    实现多线程爬虫

    • 为什么要爬虫使用多线程?
    • 为了提高抓取数据效率
    • 有些网站对访问速度有限制, 这样网站可以可以开启多个线程, 每一个线程使用一个代理,去提取页面的一部分内容
      在这里插入图片描述

    1.多线程的方法使用

    在python3中,主线程主进程结束,子线程,子进程不会结束 为了能够让主线程回收子线程,可以把子线程设置为守护线程,即该线程不重要,主线程结束,子线程结束

    t1 = threading.Thread(targe=func,args=(,))
    t1.setDaemon(True)
    t1.start() #此时线程才会启动
    

    队列模块的使用

        from queue import Queue
        q = Queue(maxsize=100)
        item = {}
        q.put_nowait(item) #不等待直接放,队列满的时候会报错
        q.put(item) #放入数据,队列满的时候回等待
        q.get_nowait() #不等待直接取,队列空的时候会报错
        q.get() #取出数据,队列为空的时候会等待
        q.qsize() #获取队列中现存数据的个数 
        q.join() #队列中维持了一个计数,计数不为0时候让主线程阻塞等待,队列计数为0的时候才会继续往后执行
        q.task_done() 
        # put的时候计数+1,get不会-1,get需要和task_done 一起使用才会-1
        ```
        ## 3. 线程中使用队列
        **队列可用于线程间的数据通讯**
        ```l
        from queue import Queue
    import threading
    
    q = Queue()
    def add_to_queue():
        for i in range(0, 100):
            print("存入队列: {}".format(i))
            q.put(i)
    
    def get_from_queue():
        # 但是在我们获取队列元素的时候, 我们并不知道队列中放了几个元素,
        # 这个时候我们就会使用while的死循环来获取,知道取完为止
        # for i in range(0, 100):
        while True:
            print("从队列中取出: {}".format(q.get()))
            q.task_done()
    
    # 创建线程
    t = threading.Thread(target=add_to_queue)
    # 设置为守护线程
    t.setDaemon(True)
    # 启动线程
    t.start()
    
    t = threading.Thread(target=get_from_queue)
    t.setDaemon(True)
    t.start()
    
    # 队列加入主线线程, 等待队列中任务完成为止
    q.join()
    
    

    装饰器的基本使用

    装饰器的作用: 不改变原有函数,给函数添加额外功能

    # 定义装饰一个死循环执行任务的装饰器
    def run_forever(func):
        def forever(obj):
            while True:
                func(obj)
        return forever
    
    # 使用装饰器
    @run_forever # 等同于 run_forever(run)
    def run(obj):
        print("人生苦短,我用Python {}".format(obj))
    
    # 执行函数
    run('Hpayy')
    
    

    糗事百科多线程

    • 实现步骤
    1. 在init方法中, 创建 URL队列, 响应队列, 数据队列
    2. 在生成URL列表中方法中,把URL添加URL队列中
    3. 在请求页面的方法中,从URL队列中取出URL执行,把获取到的响应数据添加响应队列中
    4. 在处理数据的方法中,从响应队列中取出页面内容进行解析, 把解析结果存储数据队列中
    5. 在保存数据的方法中, 从数据队列中取出数据,进行保存
    6. 开启几个线程来执行上面的方法
    • 注意: 开的线程数取决于这个任务耗时, 耗时长的就多开几个线程.
    import requests
    from lxml import etree
    import json
    from queue import Queue
    import threading
    
    '''
    1. 创建 URL队列, 响应队列, 数据队列 在init方法中
    2. 在生成URL列表中方法中,把URL添加URL队列中
    3. 在请求页面的方法中,从URL队列中取出URL执行,把获取到的响应数据添加响应队列中
    4. 在处理数据的方法中,从响应队列中取出页面内容进行解析, 把解析结果存储数据队列中
    5. 在保存数据的方法中, 从数据队列中取出数据,进行保存
    6. 开启几个线程来执行上面的方法
    '''
    
    def run_forever(func):
        def wrapper(obj):
            while True:
                func(obj)
        return wrapper
    
    
    class QiubaiSpider(object):
    
        def __init__(self):
            self.headers = {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'
            }
            self.url_pattern = 'https://www.qiushibaike.com/8hr/page/{}/'
            # url 队列
            self.url_queue = Queue()
            # 响应队列
            self.page_queue = Queue()
            # 数据队列
            self.data_queue = Queue()
    
    
        def add_url_to_queue(self):
            # 把URL添加url队列中
            for i in range(1, 14):
                self.url_queue.put(self.url_pattern.format(i))
    
        @run_forever
        def add_page_to_queue(self):
            ''' 发送请求获取数据 '''
            url = self.url_queue.get()
            # print(url)
            response = requests.get(url, headers=self.headers)
            print(response.status_code)
            if response.status_code != 200:
                self.url_queue.put(url)
            else:
                self.page_queue.put(response.content)
            # 完成当前URL任务
            self.url_queue.task_done()
    
        @run_forever
        def add_dz_to_queue(self):
            '''根据页面内容使用lxml解析数据, 获取段子列表'''
            page = self.page_queue.get()
            # print(page)
            element = etree.HTML(page)
            # 先分组,获取分组列表
            div_s = element.xpath('//*[@id="content-left"]/div')
            # 遍历分组列表, 再使用xpath获取内容
            dz_list = []
            for div in div_s:
                item = {}
                # 每个段子包含发送人头像URL, 昵称, 性别, 段子内容, 好笑数,评论数
                # 头像URL
                item['head_url'] = self.get_first_element(div.xpath('./div[1]/a[1]/img/@src'))
                if item['head_url'] is not None:
                    item['head_url'] = 'http:' + item['head_url']
    
                    # 昵称
                item['author_name'] = self.get_first_element(div.xpath('./div[1]/a[2]/h2/text()'))
                # 性别
                gender_class = self.get_first_element(div.xpath('./div[1]/div/@class'))
                if gender_class is not None:
                    item['author_gender'] = 'man' if gender_class.find('man') != -1 else 'women'
                # 段子内容
                item['dz_content'] = self.get_first_element(div.xpath('./a/div/span[1]/text()'))
    
                # 好笑数
                item['dz_funny'] = self.get_first_element(div.xpath('./div[2]/span[1]/i/text()'))
                # 评论数
                item['dz_comments'] = self.get_first_element(div.xpath('./div[2]/span[2]/a/i/text()'))
                # print(item
                dz_list.append(item)
            # print(dz_list)
            self.data_queue.put(dz_list)
            self.page_queue.task_done()
    
        def get_first_element(self, list):
            '''获取列表中第一个元素,如果是空列表就返回None'''
            return list[0] if len(list) != 0 else None
    
        @run_forever
        def save_dz_list(self):
            '''把段子信息保存到文件中'''
            dz_list = self.data_queue.get()
            # print(dz_list)
            with open('qiushi_thread.txt', 'a', encoding='utf8') as f:
                for dz in dz_list:
                    json.dump(dz, f, ensure_ascii=False)
                    f.write('\n')
            self.data_queue.task_done()
    
    
        def run_use_more_task(self, func, count=1):
            '''把func放到线程中执行, count:开启多少线程执行'''
            for i in range(0, count):
                t = threading.Thread(target=func)
                t.setDaemon(True)
                t.start()
    
        def run(self):
            # 开启线程执行上面的几个方法
            url_t = threading.Thread(target=self.add_url_to_queue)
            # url_t.setDaemon(True)
            url_t.start()
    
            self.run_use_more_task(self.add_page_to_queue, 3)
            self.run_use_more_task(self.add_dz_to_queue, 2)
            self.run_use_more_task(self.save_dz_list, 2)
    
            # 使用队列join方法,等待队列任务都完成了才结束
            self.url_queue.join()
            self.page_queue.join()
            self.data_queue.join()
    
    if __name__ == '__main__':
        qbs = QiubaiSpider()
        qbs.run()
    
    
    展开全文
  • 主要为大家详细介绍了Python多线程爬虫简单示例,感兴趣的小伙伴们可以参考一下
  • Python作为一门强大的脚本语言,我们经常使用python来写爬虫程序,简单的爬虫会写,可是用python写多线程网页爬虫,应该如何写呢?一般来说,使用线程有两种模式,一种是创建...实现python多线程(http://www.maizi...

    Python作为一门强大的脚本语言,我们经常使用python来写爬虫程序,简单的爬虫会写,可是用python写多线程网页爬虫,应该如何写呢?一般来说,使用线程有两种模式,一种是创建线程要执行的函数,把这个函数传递进Thread对象里,让它来执行.另一种是直接从Thread继承,创建一个新的class,把线程执行的代码放到这个新的class里。

    实现python多线程(http://www.maiziedu.com/group/article/10324/)网页爬虫,采用了多线程和锁机制,实现了广度优先算法的网页爬虫。

    先给大家简单介绍下我的实现思路:

    对于一个网络爬虫,如果要按广度遍历的方式下载,它是这样的:

    1.从给定的入口网址把第一个网页下载下来

    2.从第一个网页中提取出所有新的网页地址,放入下载列表中

    3.按下载列表中的地址,下载所有新的网页

    4.从所有新的网页中找出没有下载过的网页地址,更新下载列表

    5.重复3、4两步,直到更新后的下载列表为空表时停止

    python代码如下:

    #!/usr/bin/env python

    #coding=utf-8

    import threading

    import urllib

    import re

    import time

    g_mutex=threading.Condition()

    g_pages=[] #从中解析所有url链接

    g_queueURL=[] #等待爬取的url链接列表

    g_existURL=[] #已经爬取过的url链接列表

    g_failedURL=[] #下载失败的url链接列表

    g_totalcount=0 #下载过的页面数

    class Crawler:

    def __init__(self,crawlername,url,threadnum):

    self.crawlername=crawlername

    self.url=url

    self.threadnum=threadnum

    self.threadpool=[]

    self.logfile=file("log.txt",'w')

    def craw(self):

    global g_queueURL

    g_queueURL.append(url)

    depth=0

    print self.crawlername+" 启动..."

    while(len(g_queueURL)!=0):

    depth+=1

    print 'Searching depth ',depth,'... '

    self.logfile.write("URL:"+g_queueURL[0]+"........")

    self.downloadAll()

    self.updateQueueURL()

    content=' >>>Depth '+str(depth)+': '

    self.logfile.write(content)

    i=0

    while i

    content=str(g_totalcount+i)+'->'+g_queueURL+' '

    self.logfile.write(content)

    i+=1

    def downloadAll(self):

    global g_queueURL

    global g_totalcount

    i=0

    while i

    j=0

    while j

    g_totalcount+=1

    threadresult=self.download(g_queueURL[i+j],str(g_totalcount)+'.html',j)

    if threadresult!=None:

    print 'Thread started:',i+j,'--File number =',g_totalcount

    j+=1

    i+=j

    for thread in self.threadpool:

    thread.join(30)

    threadpool=[]

    g_queueURL=[]

    def download(self,url,filename,tid):

    crawthread=CrawlerThread(url,filename,tid)

    self.threadpool.append(crawthread)

    crawthread.start()

    def updateQueueURL(self):

    global g_queueURL

    global g_existURL

    newUrlList=[]

    for content in g_pages:

    newUrlList+=self.getUrl(content)

    g_queueURL=list(set(newUrlList)-set(g_existURL))

    def getUrl(self,content):

    reg=r'"(http://.+?)"'

    regob=re.compile(reg,re.DOTALL)

    urllist=regob.findall(content)

    return urllist

    class CrawlerThread(threading.Thread):

    def __init__(self,url,filename,tid):

    threading.Thread.__init__(self)

    self.url=url

    self.filename=filename

    self.tid=tid

    def run(self):

    global g_mutex

    global g_failedURL

    global g_queueURL

    try:

    page=urllib.urlopen(self.url)

    html=page.read()

    fout=file(self.filename,'w')

    fout.write(html)

    fout.close()

    except Exception,e:

    g_mutex.acquire()

    g_existURL.append(self.url)

    g_failedURL.append(self.url)

    g_mutex.release()

    print 'Failed downloading and saving',self.url

    print e

    return None

    g_mutex.acquire()

    g_pages.append(html)

    g_existURL.append(self.url)

    g_mutex.release()

    if __name__=="__main__":

    url=raw_input("请输入url入口: ")

    threadnum=int(raw_input("设置线程数:"))

    crawlername="小小爬虫"

    crawler=Crawler(crawlername,url,threadnum)

    crawler.craw()

    以上就用实例为大家讲解了python实现多线程爬虫的方法,有兴趣的朋友可以自己试试。

    展开全文
  • 本文按如下内容组织:# 介绍这个爬虫的目的、模块,创造原始单线程爬虫# 对这个爬虫进行改造,创造多线程爬虫一、爬虫功能介绍文章标题取的是《Python爬虫与多线程》,而不是《Python多线程爬虫》,因为爬虫的目的是...

    本文按如下内容组织:

    # 介绍这个爬虫的目的、模块,创造原始单线程爬虫

    # 对这个爬虫进行改造,创造多线程爬虫

    一、爬虫功能介绍

    文章标题取的是《Python爬虫与多线程》,而不是《Python多线程爬虫》,因为爬虫的目的是为了获取数据而非炫技。即使没有多线程,单线程的爬虫也可以完成任务,大不了电脑不关放一夜跑(做量化回测中常有的事)。

    下面就介绍这个爬虫的功能,是用来爬取https://quantocracy.com/所有帖子的标题、描述、网址、发布时间,分别对应数据库的四个字段:title、description、url、time。

    这个网站的结构非常简单,所以爬虫的逻辑也比较简单:

    下面依次介绍代码的实现逻辑:

    (1)构造出一页的url,比如https://quantocracy.com/?pg=1,使用自定义的get_html函数获得html内容:

    (2)使用Beautiful库解析内容,获得我们需要的信息。通过chrome的审查元素功能可以发现,网页的结构如下图:

    加粗的标签是含有信息的标签,所以我们用tags = soup.find_all('div',attrs={'class':'qo-content-col'})找到所有的div标签,每页可以得到五十个标签。

    下面使用自定义的get_info函数对每个标签做子解析:

    (3)将信息存储到本地文件或数据库。

    上述步骤(2)返回了一条[title, description, url, time]的信息,然后不断把这条信息append到results列表中,就得到了所有信息。当循环完所有页面时,我们可以把results转成pd.DataFrame,然后存储到本地csv。

    以上,我们实现了一个功能完整的单线程爬虫,耗时在十几分钟。第二部分讨论可以在哪些环节降低延迟。

    二、多线程爬虫

    上文的爬虫流程:获取页面 -> 解析页面 -> 数据存储,在这些环节中的耗时分别是:

    (1)获取页面,由于网络延迟,一页通常需要1-2s,这是最主要的延迟;

    (2)数据存储,由于是存储到本地数据库,速度较快。

    下面考虑怎么降低延迟:

    (1)创建一个Consumer类和多个实例,用于对每个页面的获取、解析和存储。

    (2)用一个队列Queue对象,来实现Consumer类不断获取网址。

    代码逻辑如下:

    先产生所有url,put进队列;

    然后产生八个消费者,用于不断从队列中取出网址,进行获取、解析和存储;

    所有信息存储到内存中,然后批量存储到数据库或csv。

    这个流程下来,有八个worker并行工作,所以效率提升很多。

    Consumer类的代码如下:

    三、最后呈现的数据长这样:

    展开全文
  • 汤不热 python 多线程爬虫
  • 虽然python多线程受GIL限制,并不是真正的多线程,但是对于I/O密集型计算还是能明显提高效率,比如说爬虫。分别用两种方式获取10个访问速度比较慢的网页,一般方式耗时50s,多线s。序:叮咚叮咚,...
  • 虽然python多线程受GIL限制,并不是真正的多线程,但是对于I/O密集型计算还是能明显提高效率,比如说爬虫。分别用两种方式获取10个访问速度比较慢的网页,一般方式耗时50s,多线s。序:叮咚叮咚,...
  • 主要介绍了使用Python多线程爬虫爬取电影天堂资源 的相关资料,需要的朋友可以参考下
  • 今天给大家分享一下python多线程爬虫与单线程爬虫时间对比 python多线程的运行效率比单线程要快的多。 我就简单举例,假如有50个url然后要获取源代码,分别用单线程和多线程,看一直运行结束后,各用多长时间...
  • Python多线程爬虫扫描器_Python源码文件,就一个PY文件,可以扫描很多内容,带注释
  • 下面小编就为大家分享一篇Python多线程爬虫实战_爬取糗事百科段子的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • Python多线程爬虫实现

    2019-06-13 20:56:46
    1. Python多线程爬虫 在批量去爬取数据的时候,往往效率会很低,这个时候我们可以用到多线程的技术。 python是支持多线程的, 主要是通过thread和threading这两个模块来实现的。 # coding=utf-8 import threading, ...
  • python多线程爬虫入门 -互斥锁以及GIL 序
  • 介绍单线程多线程,实例演示python多线程爬虫腾讯招聘。
  • 很久没写爬虫了,一个经典的Python爬虫例子,Python多线程爬虫例子案例,目标网站结构比较简单,适合练手使用,采用了经典的生产者和消费者模式,同时结合python类和装饰器的使用,...
  • python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点,在threading 得到了弥补。并且在Python3中废弃了thread模块,保留了更强大的threading模块。使用场景在python的原始解释器CPython中存在...
  • python多线程爬虫抓取网页

    千次阅读 2017-08-09 04:18:38
    python多线程爬虫抓取网页突发想法,抓取六合彩数据以便采用机器学习分析练手,网页http://www.11kj.com/kj/kjNNNN.htm,NNNN为年份。 步骤如下: 1:每一个子线程抓取每一年的网页 2:抓取网页后利用正则表达式抽取...
  • Python多线程爬虫初探—爬取豆瓣图书 top250 最近正在自学python爬虫方面的相关知识,学习到了如何使用python的urllib库进行网络爬虫,然后最近看到了多线程爬虫,于是自己也写了个小爬虫试了试多线程爬虫,把豆瓣...
  • 2019年是Python彻底崛起的一年,需求多,薪资高,掌握Python爬虫也已成为每个工程师的必备项,你get到了...本课程通过循序渐进的讲解,让学生能够利用Python多线程+生产者和消费者模式来构造一个表情包下 爬虫程序。...
  • 又是一个python爬虫的基本代码,是多线程爬虫哦,好多字啊

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,735
精华内容 11,094
关键字:

python多线程爬虫

python 订阅
爬虫 订阅