1

我正在使用 scrapy 抓取网站并从中提取数据,scrapy 使用基于正则表达式的规则来检查是否必须解析页面或必须遵循链接。

我正在为我的蜘蛛实现恢复功能,因此它可以继续从上次访问的页面爬行。为此,当蜘蛛启动时,我从数据库中获取最后一个跟踪链接。

我的网站网址看起来像http://foobar.com/page1.html,所以,通常,规则的正则表达式来跟踪每个链接,就像这样/page\d+\.html

但是我如何编写一个正则表达式使其匹配,例如第 15 页等等?另外,由于我事先不知道起点,我怎么能在运行时生成这个正则表达式?

4

4 回答 4

3

为什么不对页码进行分组,然后检查是否合格:

>>> m=re.match("/page(\d+)\.html","/page18.html")
>>> if m:
    ID=int(m.groups()[0])
>>> ID > 15
True

或更具体地说,您的要求是:

>>> def genRegex(n):
    return ''.join('[' + "0123456789"[int(d):] + ']' for d in str(n))

>>> genRegex(123)
'[123456789][23456789][3456789]'
于 2011-03-05T18:08:56.807 回答
2

稍微扩展 Kabie 的回答:

def genregex(n):
    nstr = str(n)
    same_digit = ''.join('[' + "0123456789"[int(d):] + ']' for d in nstr)
    return "\d{%d,}|%s" % (len(nstr) + 1, same_digit)

如果您的网站中出现这种情况,很容易修改以处理前导 0。但这似乎是错误的做法。

您在 scrapy 中还有其他一些选择。您可能正在使用SgmlLinkExtractor,在这种情况下,最简单的方法是将您自己的函数作为 process_value 关键字参数传递来进行自定义过滤。

您可以自定义 CrawlSpider 很多,但如果它不适合您的任务,您应该检查BaseSpider

于 2011-03-10T19:06:59.480 回答
2

尝试这个:

def digit_match_greater(n):
    digits = str(n)
    variations = []
    # Anything with more than len(digits) digits is a match:
    variations.append(r"\d{%d,}" % (len(digits)+1))
    # Now match numbers with len(digits) digits.
    # (Generate, e.g, for 15, "1[6-9]", "[2-9]\d")
    # 9s can be skipped -- e.g. for >19 we only need [2-9]\d.
    for i, d in enumerate(digits):
        if d != "9": 
            pattern = list(digits)
            pattern[i] = "[%d-9]" % (int(d) + 1)
            for j in range(i+1, len(digits)):
                pattern[j] = r"\d"
            variations.append("".join(pattern))
    return "(?:%s)" % "|".join("(?:%s)" % v for v in variations)

事实证明,让它匹配大于参数的数字更容易,所以如果你给它 15,它会返回一个匹配数字 16 和更大的字符串,特别是......

(?:(?:\d{3,})|(?:[2-9]\d)|(?:1[6-9]))

然后,您可以将其替换为您的表达式,而不是\d+,如下所示:

exp = re.compile(r"page%s\.html" % digit_match_greater(last_page_visited))
于 2011-03-05T18:49:16.820 回答
0
>>> import regex
>>> import random
>>> n=random.randint(100,1000000)
>>> n
435220
>>> len(str(n))
>>> '\d'*len(str(n))
'\\d\\d\\d\\d\\d\\d'
>>> reg='\d{%d}'%len(str(n))
>>> m=re.search(reg,str(n))
>>> m.group(0)
'435220'
于 2011-03-05T18:14:15.600 回答