推荐学习书目
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 · Feb 24, 2017 · 4028 views
    This topic created in 3364 days ago, the information mentioned may be changed or developed.

    问题

    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 replies    2017-02-25 18:10:15 +08:00
    golmic
        1
    golmic  
       Feb 24, 2017
    既然想并发的话为什么不用 scrapy
    kindjeff
        2
    kindjeff  
       Feb 24, 2017
    虽然你的问题我不知道具体的答案,但是要知道 CPython 是禁止多线程同时工作的,同一时刻只有一个线程在工作,遇到 I/O 才会切换到另一个线程。你这个程序每个线程每次都循环写入文件肯定是不合理的,需要优化。另外 Python 并发编程最合理的办法应该是不用多线程……
    Yinz
        3
    Yinz  
       Feb 24, 2017
    多打一些 log ,尽可能找出每个线程是卡在哪一句上,曾经有过类似的经历,是因为某些线程卡在了 html parse 上,原本单线程很快的 cpu 操作变得异常的慢。后来把 parse 的操作解耦放到另一个进程里面就顺畅很多了。
    kevin100702
        4
    kevin100702  
       Feb 25, 2017 via Android
    不是不推荐多线程?用子进程
    LINAICAI
        5
    LINAICAI  
       Feb 25, 2017
    线程不是你想开多少就有多少,跟系统 cpu 有关。
    binux
        6
    binux  
       Feb 25, 2017
    你不处理异常的吗?
    binux
        7
    binux  
       Feb 25, 2017
    为什么一开始频繁的使用几个线程?线程是同时执行的
    为什么先获取一段时间,然后再存储?你自己这么写的,别人怎么知道为什么!
    为什么最后只有线程 16 在工作?你加锁了啊!
    下方代码如何修改才能将多线程做到最佳?不用多线程
    Mistwave
        8
    Mistwave  
       Feb 25, 2017
    Python 有 GIL ,多线程不是很好用,一般使用协程做并发

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

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

    如此这般, python 才会真正用到多核 /超线程 处理能力。
    binux
        14
    binux  
       Feb 25, 2017
    @LittleKey #12 哪个网站?
    LittleKey
        15
    LittleKey  
       Feb 25, 2017 via Android
    @binux #14 .me 的那个。。现在又能访问了,上午说是备案什么的问题。。
    binux
        16
    binux  
       Feb 25, 2017
    @LittleKey #15 因为被墙了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   984 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 75ms · UTC 22:02 · PVG 06:02 · LAX 15:02 · JFK 18:02
    ♥ Do have faith in what you're doing.