我正在研究The List作为JS项目的刮刀,我的正则表达式可能比现在更好。
给定像
这样的数据结构<a name="may_21"><b>Wed May 21</b></a>
<ul>
<li><b><a href="by-club.0.html#Ace_of_Spades__Sacramento">Ace of Spades, Sacramento</a></b> <a href="by-band.0.html#Christina_Perri">Christina Perri</a>, <a href="by-band.0.html#Birdy">Birdy</a> a/a $20 7pm **
...
</ul>
我写了以下内容以利用cheerio来获取日期,地点和乐队列表:
request(url, (error, response, html)->
if(!error)
$ = cheerio.load(html)
concert = { bands : {}, location : {venue: "", address : ""}, date: {date: "", time: ""}}
calendar = {}
dates = []
#grab dates
$('body > ul > li > a').each(->
data = $(this)
$dates = data.children().first()
dates.push($dates.text())
)
#build concerts
for date in dates
$("a:contains('" + date + "')").siblings().each(->
$venue = $(this).children().find("b")
$bands = $venue.siblings("a")
$time = $venue.parent()#.match()
)
)
正如您所看到的,我无法弄清楚如何从上述结构中获取时间。
通常情况下,li
末尾会出现一些与特定节目相对应的纯文本,因此对于类似
我希望从
中获取“晚上8点/晚上9点”的文字<li><b><a href="by-club.0.html#Bottom_of_the_Hill__S_F_">Bottom of the Hill, S.F.</a></b> <a href="by-band.2.html#Matt_Pond_PA">Matt Pond PA</a>, <a href="by-band.2.html#Lighthouse_And_The_Whaler">Lighthouse And The Whaler</a>, <a href="by-band.1.html#Kyle_M__Terrizzi">Kyle M. Terrizzi</a> a/a $14/$16 8pm/9pm **
有时它会以“晚上8点”的形式出现,有时会是“晚上8点/ 9点”,有时根本不存在。
构建正则表达式以获取此数据的最佳方法是什么?
答案 0 :(得分:1)
不要使用完整的原始html(一般建议)。
相反,尝试将html加载到临时容器div(或documentFragment
,但需要一些自定义的基本getter-shims)。
现在按照已知的结构(循环)工作,丢弃你不需要的所有东西(如锚点),最后循环通过容器(在剩下的东西中)来获取你的最终数据(使用更简单的正则表达式,匹配例如:/(\d+[ap]m/?){1,2}$/i
。
PS,来自刮刀的一句话:一旦你完全成功完成你的刮擦,你通常只知道你的最后一个例程! (就像你通常在最后一个地方发现丢失的东西......) 正如Tomalak评论的那样:陷阱1:数据与您预期的不符。尝试研究您期望的数据格式!!
修改强>
额外建议:尽可能多地添加错误检查。尝试将您在测试过程中发现的每个漏洞转换为支票。在您开始抓取大量数据后,您需要可以获得任何帮助。
考虑一种分块方法:如果检查失败,您不需要从数据的开头重新开始。相反,添加额外的检查/解决方案并继续你的刮 否则只是测试/调试你的刮刀甚至可能看起来像DOS行为/流量。
答案 1 :(得分:0)
让这个工作,这是我最终使用的代码
fs = require('fs')
request = require('request')
cheerio = require('cheerio')
crypto = require("crypto")
url = 'http://www.foopee.com/punk/the-list/by-date.0.html'
getConcertItem = (text, regex)->
return text.match(regex)?.toString().replace(/,/g, '').trim()
request(url, (error, response, html)->
if(!error)
$ = cheerio.load(html)
#print(html)
calendar = {}
$dates = $('body > ul > li')
#dates
$dates.each(->
date = $(this).find("a").first().text()
$concerts = $(this).children("ul").children()
$concerts.each( ->
#todo: use the import-style ID generator
ID = parseInt(crypto.randomBytes(4).toString('hex'), 16)
concert = {bands : [], location : {venue: "", address : ""}, date: {date: "", time: ""}, cost: "", allAges: false}
$venue = $(this).find("b")
concert.location.venue = $venue.text()
concertText = $venue.parent().clone().children().remove().end().text()
timeRegex = /(\d?:?\d+[ap]m\/?\s?\w*\s?)/g
concert.date.date = date
concert.date.time = getConcertItem(concertText, timeRegex)
costRegex = /(\$\d+[\/-]?)/g
concert.cost = getConcertItem(concertText, costRegex)
allAgesRegex = /(a\/a)/g
if getConcertItem(concertText, allAgesRegex)
concert.allAges = true
$bands = $venue.siblings()
bands = []
$bands.each( ->
band = $(this).text()
bands.push(band)
)
concert.bands = bands
calendar[ID] = concert
)
)
)