使用 Scrapy-Splash 加载爬取一个巨大的网页
Load crawl a huge webpage with Scrapy-Splash
我的系统规格:Ubuntu 17.10、4 GB 内存、50 GB 交换空间
简而言之我的目标
我想抓取 https://www.sanego.de/Arzt/Allgemeine+Chirurgie/ 中的所有 24.453 条记录。
问题
我无法加载页面,似乎是因为它的大小
有关页面内容的更多详细信息
最初网页只显示前 30 条记录。通过单击按钮 'title="Mehr anzeigen"' 一次,我可以加载另外 +30 条记录。这可以重复直到加载所有记录。因此,它使用 javascript.
动态生成
我的总体攻略
我的想法是按下按钮 'title="Mehr anzeigen"' 直到页面上显示所有 24.453 条记录所需的次数。完成后,我将能够解析页面并收集所有记录。
Scrapy + Selenium 方法
我为此尝试了两种不同的蜘蛛。首先,我尝试通过编写一个实现 Selenium 来呈现动态内容的 Scrapy 蜘蛛来做到这一点。然而,这个解决方案在内存使用方面的成本太高。在加载大约 1500 条记录后,该进程会占用所有 RAM 并崩溃
Scrapy + Splash 方法
我假设这个解决方案可能比前一个解决方案更快,内存需求更少,但是,页面加载超过了 Splash 的最大超时限制 3600 秒,蜘蛛程序崩溃了。我将在下面只提供这个蜘蛛的代码,因为我觉得 Splash 可能是这种情况下更好的解决方案。请问你是否希望我也添加另一个。
限制内存使用
我运行 cgroups 中的每个蜘蛛都施加了 1gb 的内存限制。 spides 保持在内存限制内,但在页面完全加载之前无论如何都会崩溃。
问题
请向我提供有关如何实现目标的任何建议
代码
我就是这样开始的:
sudo cgexec -g memory:limitmem docker run -it --memory="1024m"
--memory-swappiness="100" -p 8050:8050 scrapinghub/splash --max-timeout 3600
我就是这样 运行 蜘蛛的:
sudo cgexec -g memory:limitmem scrapy crawl spersonel_spider
蜘蛛的主要部分:
from scrapy_splash import SplashRequest
import time
import json
import scrapy
from scrapy import Request
from sanego.items import PersonelItem
class SanegoSpider(scrapy.Spider):
name = "spersonel_spider"
start_urls = ['https://www.sanego.de/Arzt/Fachgebiete/','https://www.sanego.de/Zahnarzt/Fachgebiete/', 'https://www.sanego.de/Heilpraktiker/Fachgebiete/', 'https://www.sanego.de/Tierarzt/Fachgebiete/',]
def parse(self, response):
search_urls = ["https://www.sanego.de" + url for url in response.xpath('//ul[@class="itemList"]/li[contains(@class,"col-md-4")]/a/@href').extract()]
script = """
function main(splash)
local url = splash.args.url
splash.images_enabled = false
assert(splash:go(url))
assert(splash:wait(1))
local element = splash:select('.loadMore')
while element ~= nil do
assert(element:mouse_click())
assert(splash:wait{2,cancel_on_error=true})
element = splash:select('.loadMore')
end
return {
html = splash:html(),
--png = splash:png(),
--har = splash:har(),
}
end
"""
for url in search_urls:
if url == 'https://www.sanego.de/Arzt/Allgemeine+Chirurgie/':
yield SplashRequest(url, self.parse_search_results, args={'wait': 2, 'lua_source': script, 'timeout':3600},endpoint='execute', headers={'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8'})
该页面在 AJAX 上加载更多数据,因此使用简单的 Scrapy 模拟 AJAX,而不使用 Splash。
import requests
cookies = {
'sanego_sessid': 'meomk0luq31rcjl5qp38tsftp1',
'AWSELB': '0D1143B71ECAB811932E9F0030D39880BEAC9BABBC8CD3C44A99B4B781E433D347A4C2A6FDF836A5F4A4BE16334FBDA671EC87316CB08EB740C12A444F7E4A1EE15E3F26E2',
'_ga': 'GA1.2.882998560.1521622515',
'_gid': 'GA1.2.2063658924.1521622515',
'_gat': '1',
}
headers = {
'Origin': 'https://www.sanego.de',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'en-US,en;q=0.9',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
'Referer': 'https://www.sanego.de/Arzt/Allgemeine+Chirurgie/',
'X-Requested-With': 'XMLHttpRequest',
'Connection': 'keep-alive',
'DNT': '1',
}
data = [
('doctorType', 'Arzt'),
('federalStateOrMedicalArea', 'Allgemeine Chirurgie'),
('p', '1'),
('sortBy', ''),
('sortOrder', ''),
]
response = FormRequest('https://www.sanego.de/ajax/load-more-doctors-for-search', headers=headers, cookies=cookies, formdata=data)
注意 ('p', '1')
参数,并不断增加它直到到达最后一页。
我的系统规格:Ubuntu 17.10、4 GB 内存、50 GB 交换空间
简而言之我的目标
我想抓取 https://www.sanego.de/Arzt/Allgemeine+Chirurgie/ 中的所有 24.453 条记录。
问题
我无法加载页面,似乎是因为它的大小
有关页面内容的更多详细信息
最初网页只显示前 30 条记录。通过单击按钮 'title="Mehr anzeigen"' 一次,我可以加载另外 +30 条记录。这可以重复直到加载所有记录。因此,它使用 javascript.
动态生成我的总体攻略
我的想法是按下按钮 'title="Mehr anzeigen"' 直到页面上显示所有 24.453 条记录所需的次数。完成后,我将能够解析页面并收集所有记录。
Scrapy + Selenium 方法
我为此尝试了两种不同的蜘蛛。首先,我尝试通过编写一个实现 Selenium 来呈现动态内容的 Scrapy 蜘蛛来做到这一点。然而,这个解决方案在内存使用方面的成本太高。在加载大约 1500 条记录后,该进程会占用所有 RAM 并崩溃
Scrapy + Splash 方法
我假设这个解决方案可能比前一个解决方案更快,内存需求更少,但是,页面加载超过了 Splash 的最大超时限制 3600 秒,蜘蛛程序崩溃了。我将在下面只提供这个蜘蛛的代码,因为我觉得 Splash 可能是这种情况下更好的解决方案。请问你是否希望我也添加另一个。
限制内存使用
我运行 cgroups 中的每个蜘蛛都施加了 1gb 的内存限制。 spides 保持在内存限制内,但在页面完全加载之前无论如何都会崩溃。
问题
请向我提供有关如何实现目标的任何建议
代码
我就是这样开始的:
sudo cgexec -g memory:limitmem docker run -it --memory="1024m"
--memory-swappiness="100" -p 8050:8050 scrapinghub/splash --max-timeout 3600
我就是这样 运行 蜘蛛的:
sudo cgexec -g memory:limitmem scrapy crawl spersonel_spider
蜘蛛的主要部分:
from scrapy_splash import SplashRequest
import time
import json
import scrapy
from scrapy import Request
from sanego.items import PersonelItem
class SanegoSpider(scrapy.Spider):
name = "spersonel_spider"
start_urls = ['https://www.sanego.de/Arzt/Fachgebiete/','https://www.sanego.de/Zahnarzt/Fachgebiete/', 'https://www.sanego.de/Heilpraktiker/Fachgebiete/', 'https://www.sanego.de/Tierarzt/Fachgebiete/',]
def parse(self, response):
search_urls = ["https://www.sanego.de" + url for url in response.xpath('//ul[@class="itemList"]/li[contains(@class,"col-md-4")]/a/@href').extract()]
script = """
function main(splash)
local url = splash.args.url
splash.images_enabled = false
assert(splash:go(url))
assert(splash:wait(1))
local element = splash:select('.loadMore')
while element ~= nil do
assert(element:mouse_click())
assert(splash:wait{2,cancel_on_error=true})
element = splash:select('.loadMore')
end
return {
html = splash:html(),
--png = splash:png(),
--har = splash:har(),
}
end
"""
for url in search_urls:
if url == 'https://www.sanego.de/Arzt/Allgemeine+Chirurgie/':
yield SplashRequest(url, self.parse_search_results, args={'wait': 2, 'lua_source': script, 'timeout':3600},endpoint='execute', headers={'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8'})
该页面在 AJAX 上加载更多数据,因此使用简单的 Scrapy 模拟 AJAX,而不使用 Splash。
import requests
cookies = {
'sanego_sessid': 'meomk0luq31rcjl5qp38tsftp1',
'AWSELB': '0D1143B71ECAB811932E9F0030D39880BEAC9BABBC8CD3C44A99B4B781E433D347A4C2A6FDF836A5F4A4BE16334FBDA671EC87316CB08EB740C12A444F7E4A1EE15E3F26E2',
'_ga': 'GA1.2.882998560.1521622515',
'_gid': 'GA1.2.2063658924.1521622515',
'_gat': '1',
}
headers = {
'Origin': 'https://www.sanego.de',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'en-US,en;q=0.9',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
'Referer': 'https://www.sanego.de/Arzt/Allgemeine+Chirurgie/',
'X-Requested-With': 'XMLHttpRequest',
'Connection': 'keep-alive',
'DNT': '1',
}
data = [
('doctorType', 'Arzt'),
('federalStateOrMedicalArea', 'Allgemeine Chirurgie'),
('p', '1'),
('sortBy', ''),
('sortOrder', ''),
]
response = FormRequest('https://www.sanego.de/ajax/load-more-doctors-for-search', headers=headers, cookies=cookies, formdata=data)
注意 ('p', '1')
参数,并不断增加它直到到达最后一页。