在运行时生成python正则表达式以匹配从'n'到无限的数字
我正在使用scrapy这个工具来爬取一个网站并提取数据。scrapy会用一些基于正则表达式的规则来判断一个页面是否需要解析,或者一个链接是否需要跟进。
我正在为我的爬虫实现一个恢复功能,这样它就可以从上次访问的页面继续爬取。为此,我在启动爬虫时会从数据库中获取最后跟进的链接。
我的网站链接看起来像 http://foobar.com/page1.html
,所以通常来说,跟进每个这样的链接的规则正则表达式会是 /page\d+\.html
。
但是,我该如何写一个正则表达式来匹配,比如说,第15页及之后的页面呢?另外,由于我事先不知道起始点,我该如何在运行时生成这个正则表达式呢?
4 个回答
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)
如果你的网站出现了前导零,修改代码来处理这个问题其实很简单。不过,这样做似乎不是最好的方法。
在scrapy中,你还有其他几种选择。你可能在使用SgmlLinkExtractor,在这种情况下,最简单的方法就是把你自己的函数作为process_value这个参数传进去,这样就可以进行自定义过滤了。
CrawlSpider可以进行很多自定义,但如果它不适合你的任务,你可以看看BaseSpider。
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]'
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))