V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
MyFaith
V2EX  ›  Python

Python 多线程爬虫的问题

  •  
  •   MyFaith ·
    MyFaith · 2017-02-24 20:20:46 +08:00 · 3241 次点击
    这是一个创建于 2589 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题

    1. 当程序执行一段时间后就卡死了
    2. 为什么一开始频繁的使用几个线程?(下方 LOG )
    3. 为什么先获取一段时间,然后再存储?如何才能交叉执行?
    4. 为什么最后只有线程 16 在工作?
    5. 下方代码如何修改才能将多线程做到最佳?(写的第一个多线程程序,小白了) 代码:
    # coding: utf-8
    
    import requests
    from pyquery import PyQuery
    import threading
    import queue
    
    class Douyu(threading.Thread):
        def __init__(self, directory_queue, thread_name):
            self.thread_name = thread_name
            self.directory_queue = directory_queue
            self.rooms_queue = queue.Queue()
            self.lock = threading.Lock()
            threading.Thread.__init__(self)
    
        def run(self):
            self.get_rooms()
            self.lock.acquire()
            self.save_data()
            self.lock.release()
    
        def get_rooms(self):
            while not self.directory_queue.empty():
                directory_info = self.directory_queue.get_nowait()
                html = requests.get(directory_info['url']).text
                pq = PyQuery(html)
                size = pq.find('#live-list-contentbox > li').size()
                for index in range(size):
                    item = pq.find('#live-list-contentbox > li').eq(index)
                    title = item.find('a').attr('title')
                    url = 'http://www.douyu.com' + item.find('a').attr('href')
                    streamer = item.find('.dy-name').text()
                    directory = directory_info['name']
                    viewers = item.find('.dy-num').text()
                    self.rooms_queue.put({
                        'title': title,
                        'url': url,
                        'streamer': streamer,
                        'directory': directory,
                        'viewers': viewers
                    })
                    print('[%s] 获得房间: %s' %(self.thread_name, url))
    
        def save_data(self):
            while self.rooms_queue.not_empty:
                room_info = self.rooms_queue.get()
                content = '房间标题 => %s\n 主播名称 => %s\n 观众数量 => %s\n 分类栏目 => %s\n 房间链接 => %s\n\n' \
                          % (room_info['title'], room_info['streamer'], room_info['viewers'], room_info['directory'], room_info['url'])
                with open('result.txt', 'a', encoding='utf-8') as f:
                    f.write(content)
                    print('[%s] 存储房间: %s' %(self.thread_name, room_info['url']))
    
    def get_director():
        directory_queue = queue.Queue()
        html = requests.get('http://www.douyu.com/directory').text
        pq = PyQuery(html)
        size = pq.find('.unit').size()
        for index in range(size):
            item = pq.find('.unit').eq(index)
            name = item.find('p').text()
            url = item.find('a').attr('href')
            img = item.find('img').attr('data-original')
            directory_queue.put({
                'name': name,
                'url': 'http://www.douyu.com' + url,
                'img': img
            })
        return directory_queue
    
    if __name__ == '__main__':
        thread_num = 20
        threads = []
        directory_queue = get_director()
        for t in range(thread_num):
            douyu = Douyu(directory_queue, '线程%s' %str(t+1))
            print('[线程%s] 开启线程' %str(t+1))
            douyu.setDaemon(True)
            douyu.start()
            threads.append(douyu)
        for t in threads:
            t.join()
    

    LOG(分别截取了开始、中间和最后的 LOG):

    [线程 1] 获得房间: http://www.douyu.com/889024
    [线程 1] 获得房间: http://www.douyu.com/1397153
    [线程 1] 获得房间: http://www.douyu.com/110441
    [线程 1] 获得房间: http://www.douyu.com/134000
    [线程 1] 获得房间: http://www.douyu.com/854503
    [线程 3] 获得房间: http://www.douyu.com/220185
    [线程 1] 获得房间: http://www.douyu.com/796666
    [线程 1] 获得房间: http://www.douyu.com/1495611
    [线程 3] 获得房间: http://www.douyu.com/312410
    [线程 1] 获得房间: http://www.douyu.com/1061949
    [线程 3] 获得房间: http://www.douyu.com/281276
    [线程 6] 获得房间: http://www.douyu.com/659980
    [线程 1] 获得房间: http://www.douyu.com/142823
    [线程 3] 获得房间: http://www.douyu.com/127810
    [线程 6] 获得房间: http://www.douyu.com/82961
    [线程 3] 获得房间: http://www.douyu.com/lslalala
    [线程 6] 获得房间: http://www.douyu.com/yiyi0409
    [线程 1] 获得房间: http://www.douyu.com/860272
    [线程 3] 获得房间: http://www.douyu.com/85513
    [线程 6] 获得房间: http://www.douyu.com/222679
    [线程 1] 获得房间: http://www.douyu.com/529719
    [线程 1] 获得房间: http://www.douyu.com/1076249
    [线程 3] 获得房间: http://www.douyu.com/yilingshu
    [线程 6] 获得房间: http://www.douyu.com/548317
    --------------------------------------------
    [线程 1] 存储房间: http://www.douyu.com/668493
    [线程 8] 存储房间: http://www.douyu.com/1687725
    [线程 7] 存储房间: http://www.douyu.com/yueguanggugu
    [线程 9] 存储房间: http://www.douyu.com/1756041
    [线程 1] 存储房间: http://www.douyu.com/1055977
    [线程 8] 存储房间: http://www.douyu.com/1728922
    [线程 9] 存储房间: http://www.douyu.com/1646520
    [线程 7] 存储房间: http://www.douyu.com/1658595
    [线程 1] 存储房间: http://www.douyu.com/1298062
    [线程 19] 获得房间: http://www.douyu.com/1380833
    [线程 5] 获得房间: http://www.douyu.com/1001504
    [线程 7] 存储房间: http://www.douyu.com/1480669
    [线程 9] 存储房间: http://www.douyu.com/zijintv
    [线程 8] 存储房间: http://www.douyu.com/327140
    [线程 1] 存储房间: http://www.douyu.com/1733204
    [线程 7] 存储房间: http://www.douyu.com/318812
    [线程 8] 存储房间: http://www.douyu.com/550538
    [线程 9] 存储房间: http://www.douyu.com/1089301
    [线程 1] 存储房间: http://www.douyu.com/1529776
    [线程 7] 存储房间: http://www.douyu.com/psp968968
    [线程 19] 获得房间: http://www.douyu.com/1569173
    [线程 8] 存储房间: http://www.douyu.com/697983
    [线程 1] 存储房间: http://www.douyu.com/keer
    [线程 19] 存储房间: http://www.douyu.com/thp
    [线程 9] 存储房间: http://www.douyu.com/1652743
    [线程 7] 存储房间: http://www.douyu.com/xiaoermi
    [线程 5] 获得房间: http://www.douyu.com/qldyu
    [线程 8] 存储房间: http://www.douyu.com/dayage
    [线程 1] 存储房间: http://www.douyu.com/921537
    [线程 19] 存储房间: http://www.douyu.com/rentoudage
    [线程 7] 存储房间: http://www.douyu.com/1448875
    [线程 9] 存储房间: http://www.douyu.com/1586681
    [线程 8] 存储房间: http://www.douyu.com/ACE4j4f
    [线程 1] 存储房间: http://www.douyu.com/101581
    [线程 9] 存储房间: http://www.douyu.com/688037
    [线程 19] 存储房间: http://www.douyu.com/beizile
    [线程 7] 存储房间: http://www.douyu.com/SuperDongGua
    [线程 8] 存储房间: http://www.douyu.com/1632941
    [线程 5] 获得房间: http://www.douyu.com/638494
    [线程 9] 存储房间: http://www.douyu.com/1480484
    [线程 19] 存储房间: http://www.douyu.com/1707082
    [线程 1] 存储房间: http://www.douyu.com/dandansimida
    [线程 7] 存储房间: http://www.douyu.com/234796
    [线程 8] 存储房间: http://www.douyu.com/biersi
    [线程 9] 存储房间: http://www.douyu.com/973430
    [线程 8] 存储房间: http://www.douyu.com/700699
    [线程 1] 存储房间: http://www.douyu.com/1704340
    [线程 7] 存储房间: http://www.douyu.com/431834
    [线程 19] 存储房间: http://www.douyu.com/hekang26
    [线程 9] 存储房间: http://www.douyu.com/1448831
    [线程 8] 存储房间: http://www.douyu.com/1056129
    --------------------------------------------
    [线程 16] 存储房间: http://www.douyu.com/1752254
    [线程 16] 存储房间: http://www.douyu.com/432194
    [线程 16] 存储房间: http://www.douyu.com/1022771
    [线程 16] 存储房间: http://www.douyu.com/1433889
    [线程 16] 存储房间: http://www.douyu.com/1507464
    [线程 16] 存储房间: http://www.douyu.com/1609845
    [线程 16] 存储房间: http://www.douyu.com/1714938
    [线程 16] 存储房间: http://www.douyu.com/1733278
    [线程 16] 存储房间: http://www.douyu.com/1733857
    [线程 16] 存储房间: http://www.douyu.com/1756482
    [线程 16] 存储房间: http://www.douyu.com/1762073
    [线程 16] 存储房间: http://www.douyu.com/1763143
    [线程 16] 存储房间: http://www.douyu.com/560975
    [线程 16] 存储房间: http://www.douyu.com/1107272
    [线程 16] 存储房间: http://www.douyu.com/1507653
    [线程 16] 存储房间: http://www.douyu.com/1696140
    [线程 16] 存储房间: http://www.douyu.com/1747240
    [线程 16] 存储房间: http://www.douyu.com/1756615
    [线程 16] 存储房间: http://www.douyu.com/1763597
    [线程 16] 存储房间: http://www.douyu.com/1576127
    [线程 16] 存储房间: http://www.douyu.com/1715281
    [线程 16] 存储房间: http://www.douyu.com/1751258
    [线程 16] 存储房间: http://www.douyu.com/289467
    [线程 16] 存储房间: http://www.douyu.com/588167
    [线程 16] 存储房间: http://www.douyu.com/992747
    [线程 16] 存储房间: http://www.douyu.com/441593
    [线程 16] 存储房间: http://www.douyu.com/wangjiayuan
    [线程 16] 存储房间: http://www.douyu.com/941643
    [线程 16] 存储房间: http://www.douyu.com/zgzx
    [线程 16] 存储房间: http://www.douyu.com/709507
    [线程 16] 存储房间: http://www.douyu.com/1157338
    [线程 16] 存储房间: http://www.douyu.com/1127329
    [线程 16] 存储房间: http://www.douyu.com/1584630
    [线程 16] 存储房间: http://www.douyu.com/1450321
    [线程 16] 存储房间: http://www.douyu.com/1642714
    [线程 16] 存储房间: http://www.douyu.com/1064505
    [线程 16] 存储房间: http://www.douyu.com/1146092
    [线程 16] 存储房间: http://www.douyu.com/680754
    [线程 16] 存储房间: http://www.douyu.com/69832
    [线程 16] 存储房间: http://www.douyu.com/1026872
    [线程 16] 存储房间: http://www.douyu.com/810070
    [线程 16] 存储房间: http://www.douyu.com/woshidaxiang
    [线程 16] 存储房间: http://www.douyu.com/607602
    [线程 16] 存储房间: http://www.douyu.com/1233613
    [线程 16] 存储房间: http://www.douyu.com/1635785
    [线程 16] 存储房间: http://www.douyu.com/1708780
    [线程 16] 存储房间: http://www.douyu.com/1729768
    [线程 16] 存储房间: http://www.douyu.com/726729
    [线程 16] 存储房间: http://www.douyu.com/1560522
    [线程 16] 存储房间: http://www.douyu.com/1055832
    [线程 16] 存储房间: http://www.douyu.com/1661439
    [线程 16] 存储房间: http://www.douyu.com/1727351
    [线程 16] 存储房间: http://www.douyu.com/1754653
    [线程 16] 存储房间: http://www.douyu.com/856456
    [线程 16] 存储房间: http://www.douyu.com/1344011
    [线程 16] 存储房间: http://www.douyu.com/1471174
    [线程 16] 存储房间: http://www.douyu.com/1763018
    [线程 16] 存储房间: http://www.douyu.com/428860
    [线程 16] 存储房间: http://www.douyu.com/692988
    [线程 16] 存储房间: http://www.douyu.com/63279
    [线程 16] 存储房间: http://www.douyu.com/dxyd
    [线程 16] 存储房间: http://www.douyu.com/1733399
    [线程 16] 存储房间: http://www.douyu.com/1091684
    [线程 16] 存储房间: http://www.douyu.com/1547628
    [线程 16] 存储房间: http://www.douyu.com/779076
    [线程 16] 存储房间: http://www.douyu.com/1251518
    [线程 16] 存储房间: http://www.douyu.com/1729363
    [线程 16] 存储房间: http://www.douyu.com/1056938
    [线程 16] 存储房间: http://www.douyu.com/balaosiji
    [线程 16] 存储房间: http://www.douyu.com/734565
    [线程 16] 存储房间: http://www.douyu.com/1478684
    [线程 16] 存储房间: http://www.douyu.com/1667059
    [线程 16] 存储房间: http://www.douyu.com/1459180
    [线程 16] 存储房间: http://www.douyu.com/caopan
    [线程 16] 存储房间: http://www.douyu.com/1064081
    [线程 16] 存储房间: http://www.douyu.com/554746
    
    16 条回复    2017-02-25 18:10:15 +08:00
    golmic
        1
    golmic  
       2017-02-24 21:11:18 +08:00
    既然想并发的话为什么不用 scrapy
    kindjeff
        2
    kindjeff  
       2017-02-24 21:12:04 +08:00
    虽然你的问题我不知道具体的答案,但是要知道 CPython 是禁止多线程同时工作的,同一时刻只有一个线程在工作,遇到 I/O 才会切换到另一个线程。你这个程序每个线程每次都循环写入文件肯定是不合理的,需要优化。另外 Python 并发编程最合理的办法应该是不用多线程……
    Yinz
        3
    Yinz  
       2017-02-24 23:49:03 +08:00
    多打一些 log ,尽可能找出每个线程是卡在哪一句上,曾经有过类似的经历,是因为某些线程卡在了 html parse 上,原本单线程很快的 cpu 操作变得异常的慢。后来把 parse 的操作解耦放到另一个进程里面就顺畅很多了。
    kevin100702
        4
    kevin100702  
       2017-02-25 00:04:01 +08:00 via Android
    不是不推荐多线程?用子进程
    LINAICAI
        5
    LINAICAI  
       2017-02-25 00:21:27 +08:00
    线程不是你想开多少就有多少,跟系统 cpu 有关。
    binux
        6
    binux  
       2017-02-25 00:27:04 +08:00
    你不处理异常的吗?
    binux
        7
    binux  
       2017-02-25 00:30:50 +08:00
    为什么一开始频繁的使用几个线程?线程是同时执行的
    为什么先获取一段时间,然后再存储?你自己这么写的,别人怎么知道为什么!
    为什么最后只有线程 16 在工作?你加锁了啊!
    下方代码如何修改才能将多线程做到最佳?不用多线程
    Mistwave
        8
    Mistwave  
       2017-02-25 00:40:44 +08:00
    Python 有 GIL ,多线程不是很好用,一般使用协程做并发

    前几天看到一篇好文章,分享在此

    “从 0 到 1 , Python 异步编程的演进之路”: https://zhuanlan.zhihu.com/p/25228075
    binux
        9
    binux  
       2017-02-25 00:43:42 +08:00
    不对,我就不懂了,你这个 rooms_queue 也不共享,锁也不共享,你放这有什么用呢。。
    为什么最后只有线程 16 在工作?因为它干得最慢啊
    PythonAnswer
        10
    PythonAnswer  
       2017-02-25 01:27:32 +08:00 via Android
    2017 了, async await 都普及到 js 啦。
    ryd994
        11
    ryd994  
       2017-02-25 02:46:14 +08:00
    明明是个队列需求,就好好用队列库
    锁也不会用
    LittleKey
        12
    LittleKey  
       2017-02-25 09:04:27 +08:00 via Android
    @binux 你的网站挂了
    likuku
        13
    likuku  
       2017-02-25 09:53:29 +08:00
    线程处理任务队列,任务异步执行,多子进程处理任务,子进程统统后台执行。

    如此这般, python 才会真正用到多核 /超线程 处理能力。
    binux
        14
    binux  
       2017-02-25 17:59:30 +08:00
    @LittleKey #12 哪个网站?
    LittleKey
        15
    LittleKey  
       2017-02-25 18:06:31 +08:00 via Android
    @binux #14 .me 的那个。。现在又能访问了,上午说是备案什么的问题。。
    binux
        16
    binux  
       2017-02-25 18:10:15 +08:00
    @LittleKey #15 因为被墙了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3008 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 14:44 · PVG 22:44 · LAX 07:44 · JFK 10:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.