我的问题是:我想从某个域中提取所有有价值的文本,例如www.example.com。因此,我转到该网站并访问深度最大为2的所有链接,并将其写入csv文件。
我用scrapy编写了模块,使用1个进程解决了这个问题,并产生了多个爬虫,但是效率很低-我能够抓取大约1k个域/〜5k个网站/小时,据我所知,瓶颈是CPU(因为GIL?)。离开PC一段时间后,我发现网络连接断开。
当我想使用多个进程时,我只是从扭曲中得到了错误:Multiprocessing of Scrapy Spiders in Parallel Processes因此,这意味着我必须学习扭曲,与asyncio相比,我会说我不赞成使用扭曲,但这只是我的见解。
所以我有几个想法怎么办
进行反击,并尝试使用Redis来学习扭曲并实现多处理和分布式队列,但是我不认为scrapy是适合这种工作的工具。
使用pyspider-具有我需要的所有功能(我从未使用过)
适可而止-这是如此复杂(我从未使用过)
尝试构建自己的分布式搜寻器,但是在搜寻了4个网站之后,我发现了4种极端情况:SSL,重复项,超时。但是添加一些修改很容易,例如:集中爬网。
您推荐什么解决方案?
Edit1:共享代码
class ESIndexingPipeline(object):
def __init__(self):
# self.text = set()
self.extracted_type = []
self.text = OrderedSet()
import html2text
self.h = html2text.HTML2Text()
self.h.ignore_links = True
self.h.images_to_alt = True
def process_item(self, item, spider):
body = item['body']
body = self.h.handle(str(body, 'utf8')).split('\n')
first_line = True
for piece in body:
piece = piece.strip(' \n\t\r')
if len(piece) == 0:
first_line = True
else:
e = ''
if not self.text.empty() and not first_line and not regex.match(piece):
e = self.text.pop() + ' '
e += piece
self.text.add(e)
first_line = False
return item
def open_spider(self, spider):
self.target_id = spider.target_id
self.queue = spider.queue
def close_spider(self, spider):
self.text = [e for e in self.text if comprehension_helper(langdetect.detect, e) == 'en']
if spider.write_to_file:
self._write_to_file(spider)
def _write_to_file(self, spider):
concat = "\n".join(self.text)
self.queue.put([self.target_id, concat])
并致电:
def execute_crawler_process(targets, write_to_file=True, settings=None, parallel=800, queue=None):
if settings is None:
settings = DEFAULT_SPIDER_SETTINGS
# causes that runners work sequentially
@defer.inlineCallbacks
def crawl(runner):
n_crawlers_batch = 0
done = 0
n = float(len(targets))
for url in targets:
#print("target: ", url)
n_crawlers_batch += 1
r = runner.crawl(
TextExtractionSpider,
url=url,
target_id=url,
write_to_file=write_to_file,
queue=queue)
if n_crawlers_batch == parallel:
print('joining')
n_crawlers_batch = 0
d = runner.join()
# todo: print before yield
done += n_crawlers_batch
yield d # download rest of data
if n_crawlers_batch < parallel:
d = runner.join()
done += n_crawlers_batch
yield d
reactor.stop()
def f():
runner = CrawlerProcess(settings)
crawl(runner)
reactor.run()
p = Process(target=f)
p.start()
蜘蛛并不是特别有趣。
最佳答案
您可以使用Scrapy-Redis。从本质上讲,它是一个Scrapy蜘蛛,可从Redis的队列中获取URL进行爬网。
优点是您可以启动许多并发的蜘蛛,因此可以更快地进行爬网。蜘蛛程序的所有实例都会从队列中拉出URL,并在URL用完以进行爬网时等待空闲。
Scrapy-Redis的存储库附带一个示例项目来实现此目的。
我使用Scrapy-Redis启动了我的搜寻器的64个实例,在大约1小时内抓取了100万个URL。
关于python - 从scrapy提取20万个域中的文本,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41262701/