Python 多线程爬虫的问题

2017-02-24 20:20:46 +08:00
 MyFaith

问题

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

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

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

如此这般, python 才会真正用到多核 /超线程 处理能力。
binux
2017-02-25 17:59:30 +08:00
@LittleKey #12 哪个网站?
LittleKey
2017-02-25 18:06:31 +08:00
@binux #14 .me 的那个。。现在又能访问了,上午说是备案什么的问题。。
binux
2017-02-25 18:10:15 +08:00
@LittleKey #15 因为被墙了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/343000

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX