Javascript 正则表达式:如何从字符串中获取时间
我正在为一个JS项目开发一个scraper,我的正则表达式fu可能会比现在更好 给定一个数据结构,如Javascript 正则表达式:如何从字符串中获取时间,javascript,jquery,html,regex,cheerio,Javascript,Jquery,Html,Regex,Cheerio,我正在为一个JS项目开发一个scraper,我的正则表达式fu可能会比现在更好 给定一个数据结构,如 <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 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>
正如你所看到的,我很难从上面的结构中找到时间
通常,在与特定节目相对应的li
结尾会有一点纯文本,因此
<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 **
,a/a$14/$16晚上8点/9点**
有时是“8pm”,有时是“8pm/9m”,有时根本不存在
构造正则表达式以获取这些数据的最佳方法是什么?不要正则表达式完整的原始html(一般建议) 相反,尝试将html加载到临时容器div(或
documentFragment
,但需要一些自定义的基本getter)
现在通过已知的结构(循环),丢弃所有不需要的东西(如锚),最后通过容器(在剩余部分中)循环以获取最终数据(使用更简单的正则表达式,例如:/(\d+[ap]m/?){1,2}$/i
)
PS,刮刀上的一句话:通常只有在你完全成功地完成刮刀后,你才知道你的最后一个动作!(就像你通常在最后一次寻找时发现丢失的东西一样)。正如Tomalak所评论的:陷阱1:与您预期不匹配的数据。尝试研究您预期的数据格式 编辑:
额外建议:添加尽可能多的错误检查。尝试将测试期间发现的每个缺陷转化为检查。一旦开始清理大量数据,您需要任何可以得到的帮助 考虑一种分块方法:如果检查失败,您不需要从数据的开头重新开始。相反,添加额外的检查/解决方案并继续您的刮取。
否则,仅仅测试/调试你的scraper甚至可能看起来像DOS行为/流量。让它工作起来,下面是我最终使用的代码
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
)
)
)
通过查看您链接到的页面,时间格式比您在此处描述的要多。第一步,请详细列出您希望使用的每种输入格式,以及您希望从每种格式中检索的值。不要正则化完整的原始html(一般建议)。相反,尝试将html加载到临时容器div(或
documentFragment
,但您需要一些自定义的基本getter垫片)。现在以您的方式(循环)遍历已知的结构,放弃所有不需要的内容(如锚定),最后循环遍历容器以获取最终数据(使用更简单的正则表达式,匹配/(\d+[ap]m/?){1,2}$/i
(正如Tomalak所说,我认为您已经研究了预期的格式).PS,刮刀的话:只有当你完全成功地完成刮刀后,你才知道你的最后一个动作。谢谢,这非常有用。欢迎你!我把它作为你考虑的答案。太棒了,谢谢——有什么关于垫片库/示例的建议吗?没有,对不起。每个刮刀都是定制的。不过,这里有一个非常好的刮刀呃,我最近做了(该电台现在关闭了):从2013年12月8日开始的完整h4xed播放列表(现在生成更多统计数据并具有基本的文件大小估计例程):(此播放列表是用更新的刮板刮取的:)(PS:Andy知道,我共享了它以帮助拯救现在已死亡的电台的播放列表)这可能是一个更好的解决方案(提示)并涵盖了最基本的需求(但不是作为图书馆)。
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
)
)
)