首页新闻找找看学习计划

python进程池爬取速度比单线程还要慢,求一个可实现的代码方案。

0
悬赏园豆:30 [待解决问题]

一开始,我用的是单线程,爬完整个397页数据用时,其中如果不向数据库写入是62秒左右,如果要向数据库插入文件需要82

后来我改成了进程池模式,4进程爬取,其中不向数据库写入用时22秒左右 ,进程池4进程向数据库写入就要122秒.

 

我想请问下,怎样实现不太改变结构的情况下,达到多进程应该有的速度,也就是大概应该在30秒左右就可以爬完。需要一个可实现的代码方案。

 1 from bs4 import BeautifulSoup
 2 import requests
 3 import time
 4 import pymysql
 5 from multiprocessing import Pool
 6 import os
 7 t1=time.time()
 8 
 9 def multiproc(i):
10     conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='sqlxianning')
11     cursor = conn.cursor()
12     t3=time.time()
13     print('进程%s正在下载第%s页,已耗时%s'%(os.getpid(),i,t3-t1))
14     #获取网页url
15     url='http://www.0715fc.com/plus/list.php?tid=35&TotalResult=3966&nativeplace=4000&infotype=0&keyword=&PageNo=%s'%i
16     wb_data=requests.get(url)
17     #解析页面
18     soup=BeautifulSoup(wb_data.text,'lxml')
19     titles=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.fl > p:nth-of-type(1) > a')
20     areas=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.h-metre.f14.bold.pa')
21     prices=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.h-price.pa.f18.yahei.c_red')
22     for title,area,price in zip(titles,areas,prices):
23         title=title.get_text()
24         ti2=title[:10]
25         area=area.get_text()
26         a2=area[:-2]
27         price=price.get_text()
28         #数据入库
29         try:
30              cursor.execute('insert into user values ("%s","%s","%s")'%(ti2,a2,price))
31         except Exception as err:
32             print(err)
33     conn.commit()
34     cursor.close()
35     conn.close()
36 
37 if __name__=='__main__':
38     #建立进程池
39     p=Pool(4)
40     for i in range(1,398):
41         p.apply_async(multiproc,args=(i,))
42     p.close()
43     p.join()
44     t2=time.time()
45     print("总共用时%s"%(t2-t1))
Champion321的主页 Champion321 | 初学一级 | 园豆:174
提问于:2018-07-13 13:06
< >
分享
所有回答(3)
0

跟你的数据库配置有关系吧

Klong | 园豆:202 (菜鸟二级) | 2018-07-13 13:36

那请教下该如何配置,或者说数据库哪里可能存在问题?单线程用的也是这个库这个表。这个应该是我把数据库的连接和关闭放在了循环里面,导致频繁连接,打开,提交事务引起的。

支持(0) 反对(0) Champion321 | 园豆:174 (初学一级) | 2018-07-13 13:42
0

你电脑感觉有些慢啊。。就下面简单改了两下在我电脑上快了近一倍

if __name__=='__main__':
#建立进程池
p=Pool(4)
conn = pymysql.connect(host='localhost', port=3306, user='root', passwd=None, db="crawler", charset="utf8")
cursor = conn.cursor()
s = requests.Session()
for i in range(1,398):
p.apply_async(multiproc,args=(i, s, cursor))
cursor.close()
conn.close()
p.close()
p.join()
t2=time.time()
print("总共用时%s"%(t2-t1))

程序执行应该费不了什么时间,主要是网络请求和数据库连接写这两个费时,所以一个是把数据库连接放外面,还有就是建立一个会话这两点优化就能快很多

如果还想更加优化可以把数据库连接插入搞个进程里面加个缓存达到一定量再批量插入,其他抓取搞多个进程,类似生产消费者,这样效率应该会更高。

水墨的心 | 园豆:361 (菜鸟二级) | 2018-07-13 14:22

您好,能麻烦您贴下全部代码吗,因为我改完还是在报错。应该是我哪里没有注意到。谢谢您。应该主要是(multiproc,args=(i,s,cursor))这后面两个参数怎么传我没有理会到。

支持(0) 反对(0) Champion321 | 园豆:174 (初学一级) | 2018-07-13 14:57

@Champion321: 

 1 from bs4 import BeautifulSoup
 2 import requests
 3 import time
 4 import pymysql
 5 from multiprocessing import Pool
 6 import os
 7 t1=time.time()
 8 
 9 def multiproc(i, s, cursor):
10     t3=time.time()
11     print('进程%s正在下载第%s页,已耗时%s'%(os.getpid(),i,t3-t1))
12     #获取网页url
13     url='http://www.0715fc.com/plus/list.php?tid=35&TotalResult=3966&nativeplace=4000&infotype=0&keyword=&PageNo=%s'%i
14     wb_data=s.get(url)
15     #解析页面
16     soup=BeautifulSoup(wb_data.text,'lxml')
17     titles=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.fl > p:nth-of-type(1) > a')
18     areas=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.h-metre.f14.bold.pa')
19     prices=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.h-price.pa.f18.yahei.c_red')
20     for title,area,price in zip(titles,areas,prices):
21         title=title.get_text()
22         ti2=title[:10]
23         area=area.get_text()
24         a2=area[:-2]
25         price=price.get_text()
26         #数据入库
27         try:
28              cursor.execute('insert into user values ("%s","%s","%s")'%(ti2,a2,price))
29         except Exception as err:
30             print(err)
31     conn.commit()
32 
33 if __name__=='__main__':
34     #建立进程池
35     p=Pool(4)
36     conn = pymysql.connect(host='localhost', port=3306, user='root', passwd=None, db="crawler", charset="utf8")
37     cursor = conn.cursor()
38     s = requests.Session()
39     for i in range(1,398):
40         p.apply_async(multiproc,args=(i, s, cursor))
41     cursor.close()
42     conn.close()
43     p.close()
44     p.join()
45     t2=time.time()
46     print("总共用时%s"%(t2-t1))

就把requests.get换成s.get,其他不变。创建一个会话可以保留一些参数和cookie而且会话期间底层的TCP是不会断的,你可以看下官方文档里的描述http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

支持(1) 反对(0) 水墨的心 | 园豆:361 (菜鸟二级) | 2018-07-13 18:54

@水墨的心: 您好,我按照您给的方法去尝试,但是总是报错Cursor closed,同时数据库中并不会有数据存进去,您测试的时候数据库里会有文件写入吗?还请您再帮我看下。不胜感激。

 1 from bs4 import BeautifulSoup
 2 import requests
 3 import time
 4 import pymysql
 5 from multiprocessing import Pool
 6 import os
 7 t1=time.time()
 8 
 9 def multiproc(i,s,cursor):
10     t3=time.time()
11     print('进程%s正在下载第%s页,已耗时%s'%(os.getpid(),i,t3-t1))
12     #获取网页url
13     url='http://www.0715fc.com/plus/list.php?tid=35&TotalResult=3966&nativeplace=4000&infotype=0&keyword=&PageNo=%s'%i
14     wb_data=s.get(url)
15     #解析页面
16     soup=BeautifulSoup(wb_data.text,'lxml')
17     titles=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.fl > p:nth-of-type(1) > a')
18     areas=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.h-metre.f14.bold.pa')
19     prices=soup.select('#content > div.site-section > div.site-house-list.clearfix > dl > dd.h-price.pa.f18.yahei.c_red')
20     for title,area,price in zip(titles,areas,prices):
21         title=title.get_text()
22         ti2=title[:10]
23         area=area.get_text()
24         a2=area[:-2]
25         price=price.get_text()
26         #数据入库
27         try:
28              cursor.execute('insert into user values ("%s","%s","%s")'%(ti2,a2,price))
29         except Exception as err:
30             print(err)
31     conn.commit()
32 
33 
34 if __name__=='__main__':
35     #建立进程池
36     p=Pool(4)
37     conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='sqlxianning')
38     cursor = conn.cursor()
39     s = requests.Session()
40     for i in range(1,398):
41         p.apply_async(multiproc,args=(i,s,cursor))
42     cursor.close()
43     conn.close()
44     p.close()
45     p.join()
46     t2=time.time()
47     print("总共用时%s"%(t2-t1))
支持(0) 反对(1) Champion321 | 园豆:174 (初学一级) | 2018-07-13 19:13
0

将数据库连接放在最前面声明,在p.join()后关闭。测试后可以在28秒至30秒之间爬完。

Champion321 | 园豆:174 (初学一级) | 2018-07-24 17:32
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册