windows中使用multiprocessing报错 RuntimeError: An attempt has been made to start a new process......

版权声明:站在巨人的肩膀上学习。 https://blog.csdn.net/zgcr654321/article/details/82844879

RuntimeError: 

An attempt has been made to start a new process before the current process has finished its bootstrapping phase.

This probably means that you are not using fork to start your child processes and you have forgotten to use the proper idiom in the main module。

multiprocessing的使用在Linux和mac中都可以直接使用,但是在windows中,必须加上if __name__ == ‘__main__’:

if __name__ == ‘__main__’:加在p=Process()或pool = mp.Pool(4)之前,并把之后的执行语句全放到if以内。

如:

import multiprocessing as mp
# 需要使用多进程模块
import time
from urllib.request import urlopen, urljoin
from bs4 import BeautifulSoup
import re

# urlopen爬取网页,BeautifulSoup解析网页
base_url = 'https://morvanzhou.github.io/'


def crawl(url):
	response = urlopen(url)
	return response.read().decode('utf-8')


# 返回爬取的网页

def parse(html):
	# 解析函数
	soup = BeautifulSoup(html, 'lxml')
	# 解析网页
	urls = soup.find_all('a', {"href": re.compile('^/.+?/$')})
	# ^匹配字符串的开头。
	# $匹配字符串的末尾。
	# /顺斜杠是表示表达式开始和结束的“定界符”。
	# \反斜杠是表示转义字符。
	# .+?表示匹配任意字符并最小匹配。
	title = soup.find('h1').get_text().strip()
	# strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
	page_urls = set([urljoin(base_url, url['href']) for url in urls])
	# 上面一句是为了去除重复网址,set集合里的元素是不会重复的,urljoin就是将基地址与一个相对地址形成一个绝对地址
	url = soup.find('meta', {'property': 'og:url'})['content']
	# 该网站源代码中表示网页链接的标签均为meta,且property值为og:url,我们只需要其content部分的内容,即链接本身
	return title, page_urls, url


unseen = set([base_url, ])
# 未爬取的网页集合
seen = set()
# 已经爬取的网页的集合,初始为0
if __name__ == '__main__':
	# 在windows中用multiprocessing必须加上上面这句if __name__ == '__main__':,否则会报错!
	pool = mp.Pool(4)
	# 创建一个进程池,最多可以同时运行4个进程
	count, t1 = 1, time.time()
	while len(unseen) != 0:
		if len(seen) > 20:
			break
		# 爬取超过20个页面则中断
		crawl_jobs = [pool.apply_async(crawl, args=(url,)) for url in unseen]
		# apply_async()本身就可以返回被进程调用的函数的返回值。
		# 如果在函数func中返回一个值,那么pool.apply_async(func, (msg, ))的结果就是返回pool中所有进程的值的对象。
		# pool.apply_async()是apply()函数的变体。它既是Pool的方法,也是Python内置的函数,两者等价。
		# apply()是阻塞的。主进程会被阻塞直到函数执行结束。
		# apply_async 是异步非阻塞的。完全没有等待子进程执行完毕,主进程就已经执行完毕,并退出程序。
		print('\n开始爬取网页')
		htmls = [j.get() for j in crawl_jobs]
		# 得到抓取的所有页面
		print('\n开始解析网页')
		parse_jobs = [pool.apply_async(parse, args=(html,)) for html in htmls]
		# 分析页面,同样使用pool.apply_async()
		# 把抓取页面信息和分析页面信息这两步由原来的循环执行改为多进程执行
		results = [j.get() for j in parse_jobs]
		print('\n分析网页')
		seen.update(unseen)
		#  update()函数把字典unseen的键/值对更新到seen里。
		unseen.clear()
		# 删除字典内所有元素

		for title, page_urls, url in results:
			print(count, title, url)
			# 打印爬取的网页编号、标题和链接地址
			count += 1
			unseen.update(page_urls - seen)
	# 更新unseen为还未爬取的链接集合

	print('total time:%.1f s' % (time.time() - t1,))

猜你喜欢

转载自blog.csdn.net/zgcr654321/article/details/82844879