热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#我自己做一个网站图片的抓取

我自己做了一个网站图片的抓取,感觉速度有点慢抓取4000张图片可能得用15分钟左右的时间,我百度看用线程可以加快抓取,然后创建了5个线程抓取,但是5个线程是同步执行同样的操作一个图片就
我自己做了一个网站图片的抓取, 感觉速度有点慢抓取4000张图片 可能得用15分钟左右的时间,
我百度看 用线程可以加快抓取,然后创建了5个线程抓取,但是 5个线程是同步执行 同样的操作 一个图片就抓取了5次,
代码应该怎么写 才能让线程 不抓取同样的内容呢

38 个解决方案

#1


用个List记录你抓的图片啊。抓过就弄下一个。

#2


引用 1 楼 qq_20324803 的回复:
用个List记录你抓的图片啊。抓过就弄下一个。

但是我看 线程是同步执行的啊 ,- -  一个方法执行 5次 不是更慢了么,加了list 以后 还要加判断 不是更慢了..

#3


若图片平均大小为 1M,那么 4000 / (15 * 60) = 4.44 M/s
也就是你这少需要 30M 线路带宽,已经很快了
如果开宽还有富裕,是可以考虑用多线程的
你可以设一个待抓取图片的队列,每个线程只从队首取出图片 url,这样就不会重复了
如果抓取失败,还应将相应 url 重新入队

#4


引用 3 楼 xuzuning 的回复:
若图片平均大小为 1M,那么 4000 / (15 * 60) = 4.44 M/s
也就是你这少需要 30M 线路带宽,已经很快了
如果开宽还有富裕,是可以考虑用多线程的
你可以设一个待抓取图片的队列,每个线程只从队首取出图片 url,这样就不会重复了
如果抓取失败,还应将相应 url 重新入队

图片没有那个大 平均大小150K左右的 
我是这样写的  - -不知道是不是有问题
 Thread[] download;
            ThreadStart start = new System.Threading.ThreadStart(uploadimg);
            download = new Thread[5];
            for (int i = 0; i < 5; i++)
            {
                download[i] = new System.Threading.Thread(start);
                download[i].Start();
            }

#5


关键在于你的 uploadimg 是怎么写的

#6


引用 5 楼 xuzuning 的回复:
关键在于你的 uploadimg 是怎么写的

这是我主要的代码

#7


页号(序数)应作为参数传入,而不是在  uploadimg 中循环产生
也就是 uploadimg 方法每次抓取一个页面中的图片

#8


引用 7 楼 xuzuning 的回复:
页号(序数)应作为参数传入,而不是在  uploadimg 中循环产生
也就是 uploadimg 方法每次抓取一个页面中的图片


我理解你的这个说法- -现在纠结的是我不会用线程.就是不知道线程该咋样写呀

#9


分批次。
多线程编程,关键在于分派任务。
可以使用一个队列存储url,每次线程从队列中获取一批url(加锁,或者使用线程安全的队列)。

#10


引用 9 楼 zhi_ai_yaya 的回复:
分批次。
多线程编程,关键在于分派任务。
可以使用一个队列存储url,每次线程从队列中获取一批url(加锁,或者使用线程安全的队列)。


了解,我去改进一下

#11


如果要用多线程去抓
首先你得取得所有图片链接列表
然后根据线程数量去为每一个线程分配好
再运行那些线程,最好不要线程运行的时候再去取全部图片列表,那样还得加互斥,影响效率

#12


给你个控制台演示代码你体会一下
        static void Main(string[] args)
        {
            var tasks = Enumerable.Range(0, 50);
            var q = from x in tasks.AsParallel().WithDegreeOfParallelism(5)
                    select DoIt(x);
            Console.WriteLine("总共用了{0}个线程执行了{1}个任务!\n", q.Distinct().Count(), tasks.Count());
        }
        static int DoIt(int n)
        {
            var tid = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("{0} : {1}", tid, n);
            return tid;
        }

#13


引用 11 楼 stherix 的回复:
如果要用多线程去抓
首先你得取得所有图片链接列表
然后根据线程数量去为每一个线程分配好
再运行那些线程,最好不要线程运行的时候再去取全部图片列表,那样还得加互斥,影响效率


- -这样不就不智能了么

#14


引用 13 楼 sinat_25186077 的回复:
Quote: 引用 11 楼 stherix 的回复:

如果要用多线程去抓
首先你得取得所有图片链接列表
然后根据线程数量去为每一个线程分配好
再运行那些线程,最好不要线程运行的时候再去取全部图片列表,那样还得加互斥,影响效率


- -这样不就不智能了么


如果图片不是大小差不多的话 按数量来分配是不好
那就要互斥去图片池里取图片链接 然后下载

#15


为每一个线程都分配不同的图片网址,这样下载的就不会重复了。

#16


引用 11 楼 stherix 的回复:
如果要用多线程去抓
首先你得取得所有图片链接列表
然后根据线程数量去为每一个线程分配好
再运行那些线程,最好不要线程运行的时候再去取全部图片列表,那样还得加互斥,影响效率


这理解就不打对了吧:
假如有5个线程,10000条url。则list.count=10000.

假如一张图片100kb,那100张图片就是10M,就算,100M宽带,则一秒钟10M下行速度,则5秒钟内,恰好五个线程执行一轮。(这是最完美的分配)。

那么,对于任务线程1而言,花5秒钟执行一遍,然后去队列加锁读取100个url元素(这个操作几毫秒就完成了吧)。

那么,5秒内,只有n个线程请求加锁,加锁时间是几毫秒,而且由于时间片的缘故,极大概率是分时请求而不是同时请求,所以这个互斥的影响,其实是可以忽略不计的。

假如提高100这个数字,比如提高到1000,则这个队列加锁是毫无压力的。

------------
就好比10个楼盘销售人员跟房产开发商合作,卖掉1000套房子一样。
每次销售人员都分配5套,谁卖掉5套了再回来找房产开发商登记。
不用想,房产开发商肯定闲得蛋疼。

#17



private Queue m_que_url = new Queue();

private void DownLoadCallBack() {
    string strUrl = string.Empty;
    WebClient web = new WebClient();
    while (true) {
        lock (m_que_url) {
            if (m_que_url.Count == 0) break;
            strUrl = m_que_url.Dequeue();
        }
        try {
            web.DownloadFile(strUrl, "yourfilename");
        } catch (Exception ex) {
            Console.WriteLine(ex.Message);
        }
    }
}

//set m_que_url
int nThreadCount  = 50;
for (int i = 0; i < nThreadCount; i++) {
    new Thread(DownLoadCallBack) { IsBackground = true }.Start();
}

#18


先mark,节后我回来收取代码 刚好有上百万张图片url要抓,虽然大部分不怎样,但有小部分是很给力的图片 方便的话贴段代码,感谢楼主

#19


引用 18 楼 zhi_ai_yaya 的回复:
先mark,节后我回来收取代码 刚好有上百万张图片url要抓,虽然大部分不怎样,但有小部分是很给力的图片 方便的话贴段代码,感谢楼主

 - - 要我的代码 干嘛

#20


引用 17 楼 crystal_lz 的回复:

private Queue m_que_url = new Queue();

private void DownLoadCallBack() {
    string strUrl = string.Empty;
    WebClient web = new WebClient();
    while (true) {
        lock (m_que_url) {
            if (m_que_url.Count == 0) break;
            strUrl = m_que_url.Dequeue();
        }
        try {
            web.DownloadFile(strUrl, "yourfilename");
        } catch (Exception ex) {
            Console.WriteLine(ex.Message);
        }
    }
}

//set m_que_url
int nThreadCount  = 50;
for (int i = 0; i < nThreadCount; i++) {
    new Thread(DownLoadCallBack) { IsBackground = true }.Start();
}
兄台你好眼熟啊 -- 

#21


引用 17 楼 crystal_lz 的回复:

private Queue m_que_url = new Queue();

private void DownLoadCallBack() {
    string strUrl = string.Empty;
    WebClient web = new WebClient();
    while (true) {
        lock (m_que_url) {
            if (m_que_url.Count == 0) break;
            strUrl = m_que_url.Dequeue();
        }
        try {
            web.DownloadFile(strUrl, "yourfilename");
        } catch (Exception ex) {
            Console.WriteLine(ex.Message);
        }
    }
}

//set m_que_url
int nThreadCount  = 50;
for (int i = 0; i < nThreadCount; i++) {
    new Thread(DownLoadCallBack) { IsBackground = true }.Start();
}
 看起来 不错

#22


引用 20 楼 sinat_25186077 的回复:
Quote: 引用 17 楼 crystal_lz 的回复:


private Queue m_que_url = new Queue();

private void DownLoadCallBack() {
    string strUrl = string.Empty;
    WebClient web = new WebClient();
    while (true) {
        lock (m_que_url) {
            if (m_que_url.Count == 0) break;
            strUrl = m_que_url.Dequeue();
        }
        try {
            web.DownloadFile(strUrl, "yourfilename");
        } catch (Exception ex) {
            Console.WriteLine(ex.Message);
        }
    }
}

//set m_que_url
int nThreadCount  = 50;
for (int i = 0; i < nThreadCount; i++) {
    new Thread(DownLoadCallBack) { IsBackground = true }.Start();
}
兄台你好眼熟啊 -- 

是不是在你梦里出现过。。

#23


引用 22 楼 crystal_lz 的回复:
Quote: 引用 20 楼 sinat_25186077 的回复:

Quote: 引用 17 楼 crystal_lz 的回复:


private Queue m_que_url = new Queue();

private void DownLoadCallBack() {
    string strUrl = string.Empty;
    WebClient web = new WebClient();
    while (true) {
        lock (m_que_url) {
            if (m_que_url.Count == 0) break;
            strUrl = m_que_url.Dequeue();
        }
        try {
            web.DownloadFile(strUrl, "yourfilename");
        } catch (Exception ex) {
            Console.WriteLine(ex.Message);
        }
    }
}

//set m_que_url
int nThreadCount  = 50;
for (int i = 0; i < nThreadCount; i++) {
    new Thread(DownLoadCallBack) { IsBackground = true }.Start();
}
兄台你好眼熟啊 -- 

是不是在你梦里出现过。。
可能是看别的帖子的时候 看到了你的发言了吧

#24


这个东西。我第一个想到的是Paralel。for。

#25


该回复于2016-10-01 08:48:51被管理员删除

#26


5个线程访问同样一个方法,还没有参数,5次调用都在干同样的事情当然重复下载了,你弄点参数进去,让第一个线程干1---5 ,第二个现场6-10 。。。。。。

#27


用了 并行加线程处理以后 速度快多了  O(∩_∩)O哈哈~

#28


我觉得异步会快些吧

#29


引用 28 楼 liucqa 的回复:
我觉得异步会快些吧
 异步还没用  还没比较

#30


我又回来了!!

#31


如果网站请求等待时间长的话,异步的好处就体现出来了,在等待网站返回的时间,可以发1000个请求了,然后慢慢等着回来

#32


引用 30 楼 zhi_ai_yaya 的回复:
我又回来了!!

怎么给代码你 ,没看到传文件的呀

#33


引用 32 楼 sinat_25186077 的回复:
Quote: 引用 30 楼 zhi_ai_yaya 的回复:

我又回来了!!

怎么给代码你 ,没看到传文件的呀

哟西,非常感谢~~
把代码直接张贴上来就OK啦。
如果是demo,包含解决方案,引用库之类的,可以上传到CSDN下载,让大家可以下载,然后张贴下载链接到帖子后面。

讨论一个问题,最后得到一些解决办法,作为总结放到帖子最后,然后结贴。论坛本来就应该这样的

#34


引用 33 楼 zhi_ai_yaya 的回复:
Quote: 引用 32 楼 sinat_25186077 的回复:

Quote: 引用 30 楼 zhi_ai_yaya 的回复:

我又回来了!!

怎么给代码你 ,没看到传文件的呀

哟西,非常感谢~~
把代码直接张贴上来就OK啦。
如果是demo,包含解决方案,引用库之类的,可以上传到CSDN下载,让大家可以下载,然后张贴下载链接到帖子后面。

讨论一个问题,最后得到一些解决办法,作为总结放到帖子最后,然后结贴。论坛本来就应该这样的

 - - 我电脑上只有最初版的,修改的不在我电脑上,不过我先传上去吧,你自己改改 哈哈

#35


http://down.51cto.com/data/2248694
最初版本的代码 传上去了  有需要的自己看看啊,csdn 上面的我传上去没显示 没得办法,换了个网站传了

#36


用MD5码,可能会好一些,MD5码可以识别文件的不同。

#37


七天,不足以表达我对祖国母亲的热爱。经过这七天,我总是在深思,伟大的祖国母亲为什么不再过一个阴历生日呢?
开工了,从今天起我才知道未来七天其实不短。

#38


引用 3 楼 xuzuning 的回复:
若图片平均大小为 1M,那么 4000 / (15 * 60) = 4.44 M/s
也就是你这少需要 30M 线路带宽,已经很快了
如果开宽还有富裕,是可以考虑用多线程的
你可以设一个待抓取图片的队列,每个线程只从队首取出图片 url,这样就不会重复了
如果抓取失败,还应将相应 url 重新入队

版主说的非常对,大家都要这样做,代码就会很稳定了。

推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文探讨了在Java多线程环境下,如何确保具有相同key值的线程能够互斥执行并按顺序输出结果。通过优化代码结构和使用线程安全的数据结构,我们解决了线程同步问题,并实现了预期的并发行为。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 当unique验证运到图片上传时
    2019独角兽企业重金招聘Python工程师标准model:public$imageFile;publicfunctionrules(){return[[[na ... [详细]
  • Struts与Spring框架的集成指南
    本文详细介绍了如何将Struts和Spring两个流行的Java Web开发框架进行整合,涵盖从环境配置到代码实现的具体步骤。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 本文详细探讨了如何通过分析单个或多个线程在瓶颈情况下的表现,来了解处理器资源的消耗。无论是单进程还是多进程环境,监控关键指标如线程数量、占用时间及调度优先级等,有助于揭示潜在的性能问题。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • 本文档汇总了Python编程的基础与高级面试题目,涵盖语言特性、数据结构、算法以及Web开发等多个方面,旨在帮助开发者全面掌握Python核心知识。 ... [详细]
author-avatar
手机用户2602887787
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有