我正在为使用CrawlSpider scrapy的网站编写一个抓取工具。
Scrapy提供了一个内置的重复请求过滤器,可根据网址过滤重复的请求。此外,我可以使用CrawlSpider的规则成员过滤请求。
我想要做的是过滤以下请求:
http:://www.abc.com/p/xyz.html?id=1234&refer=5678
如果我已经访问过
http:://www.abc.com/p/xyz.html?id=1234&refer=4567
注意: refer是一个不影响我得到的响应的参数,所以我不在乎该参数的值是否会发生变化。
现在,如果我有一个累积所有 ids 的集合,我可以在我的回调函数 parse_item (这是我的回调函数)中忽略它来实现此功能。
但这意味着当我不需要时,我仍然至少会抓取那个页面。
那么我告诉scrapy它不应该根据网址发送特定请求的方式是什么?
答案 0 :(得分:39)
您可以编写自定义中间件以进行重复删除,并将其添加到设置中
import os
from scrapy.dupefilter import RFPDupeFilter
class CustomFilter(RFPDupeFilter):
"""A dupe filter that considers specific ids in the url"""
def __getid(self, url):
mm = url.split("&refer")[0] #or something like that
return mm
def request_seen(self, request):
fp = self.__getid(request.url)
if fp in self.fingerprints:
return True
self.fingerprints.add(fp)
if self.file:
self.file.write(fp + os.linesep)
然后你需要在settings.py
中设置正确的DUPFILTER_CLASSDUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter'
它应该在那之后工作
答案 1 :(得分:10)
在ytomar的带领下,我编写了这个过滤器,它基于通过检查内存集已经看到的URL进行过滤。我是一个Python noob,所以如果我搞砸了,请告诉我,但它似乎可以正常工作:
from scrapy.dupefilter import RFPDupeFilter
class SeenURLFilter(RFPDupeFilter):
"""A dupe filter that considers the URL"""
def __init__(self, path=None):
self.urls_seen = set()
RFPDupeFilter.__init__(self, path)
def request_seen(self, request):
if request.url in self.urls_seen:
return True
else:
self.urls_seen.add(request.url)
正如ytomar所提到的,请务必将DUPEFILTER_CLASS
常量添加到settings.py
:
DUPEFILTER_CLASS = 'scraper.custom_filters.SeenURLFilter'
答案 2 :(得分:3)
https://github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py
此文件可能对您有所帮助。此文件从url创建唯一delta获取密钥的数据库,用户在scrapy中传递.Reqeust(meta = {'deltafetch_key':uniqe_url_key})。 这样,您就可以避免过去曾经访问过的重复请求。
使用deltafetch.py
的示例mongodb实现 if isinstance(r, Request):
key = self._get_key(r)
key = key+spider.name
if self.db['your_collection_to_store_deltafetch_key'].find_one({"_id":key}):
spider.log("Ignoring already visited: %s" % r, level=log.INFO)
continue
elif isinstance(r, BaseItem):
key = self._get_key(response.request)
key = key+spider.name
try:
self.db['your_collection_to_store_deltafetch_key'].insert({"_id":key,"time":datetime.now()})
except:
spider.log("Ignoring already visited: %s" % key, level=log.ERROR)
yield r
例如。 id = 345 scrapy.Request(URL,元= {deltafetch_key:345},回调=解析)
答案 3 :(得分:1)
这是我的自定义过滤器基于scrapy 0.24.6。
在此过滤器中,它只关注网址中的id。例如
import re
import os
from scrapy.dupefilter import RFPDupeFilter
class MyCustomURLFilter(RFPDupeFilter):
def _get_id(self, url):
m = re.search(r'(\d+)\.html', url)
return None if m is None else m.group(1)
def request_fingerprint(self, request):
style_id = self._get_id(request.url)
return style_id
retainAll
被视为相同的网址。但
public List<Bongo> getBongos(List<String> names) {
Map<String, Wongo> copy = new HashMap<>(nameToWongoMap);
copy.keySet().retainAll(names);
return copy.values().stream().map(Bongo::new).collect(
Collectors.toList());
}
不会。
SELECT * FROM XSales_Code SC
WHERE SC.Status = 1
AND SC.SCode NOT IN
(
SELECT DISTINCT SCode FROM XTransactions_01
WHERE Last_Mdt > '2012-01-01'
AND SCode IS NOT NULL
)
AND SC.Last_Mdt < '2014-01-01'
ORDER BY Last_Mdt desc
答案 4 :(得分:0)
在最新的scrapy中,我们可以使用默认的复制过滤器或扩展并具有自定义过滤器。
在蜘蛛设置中定义以下配置
private var blankWindow: BlankWindow?
// MARK: Shared AppDelegate
extension AppDelegate {
static func blankWindowShouldAppear(blankWindow: inout BlankWindow?) {
blankWindow = BlankWindow(frame: UIScreen.main.bounds)
blankWindow?.makeKeyAndVisible()
}
static func blankWindowShouldDisappear(window: UIWindow?, blankWindow: inout BlankWindow?) {
window?.makeKeyAndVisible()
blankWindow = nil
}
@available(iOS 13.0, *)
static func blankWindowShouldAppear(_ windowScene: UIWindowScene, blankWindow: inout BlankWindow?) {
blankWindow = BlankWindow(windowScene: windowScene)
blankWindow?.makeKeyAndVisible()
}
}
// MARK: Old life cycle methods
extension AppDelegate {
/// ⚠️ Methods here will not be called under iOS 13 due to new SceneDelegate life cycle
func applicationWillEnterBackground(_ application: UIApplication) {
AppDelegate.blankWindowShouldAppear(blankWindow: &blankWindow)
}
func applicationWillEnterForeground(_ application: UIApplication) {
AppDelegate.blankWindowShouldDisappear(window: window, blankWindow: &blankWindow)
}
}