欢迎回到有关构建网络刮板的系列文章。 在本教程中,我将通过一个示例从我自己的播客站点中抓取数据。 我将详细介绍如何提取数据,辅助方法和实用程序方法如何完成其​​工作以及所有难题之类如何组合在一起。

主题

  • 刮我的播客
  • 刮刀
  • 辅助方法
  • 写文章

刮我的播客

让我们将到目前为止所学的知识付诸实践。 由于各种原因,请重新设计我的播客。 屏幕早就该过期了。 当我早上醒来时,有些问题使我尖叫。 因此,我决定建立一个由Middleman构建并由GitHub Pages托管的全新静态站点。

在根据自己的需要调整了Middleman博客之后,我在新设计上投入了大量时间。 剩下要做的就是从我的数据库支持的Sinatra应用程序中导入内容,因此我需要抓取现有内容并将其转移到新的静态站点中。

因为我可以依靠我的朋友Nokogiri和Mechanize来为我做这份工作,所以以schmuck方式手工完成此任务不是摆在桌子上,甚至不是问题。 摆在您面前的是一个相当小的刮刮工作,它不太复杂,但是提供了一些有趣的转折,对于那些在网上刮刮新手的工作应该是有教益的。

以下是我的播客的两个屏幕截图。

截图旧播客


截图新播客


让我们分解一下我们想要完成的工作。 我们希望从139个情节(分布在21个分页的索引站点中)中提取以下数据:

  • 标题
  • 受访者
  • 带有主题列表的子标题
  • 每个剧集的SoundCloud曲目号
  • 日期
  • 剧集编号
  • 演出笔记中的文字
  • 显示笔记中的链接

我们遍历分页,让Mechanize单击情节的每个链接。 在下面的详细信息页面上,我们将在上面找到所需的所有信息。 使用刮的数据,我们要填充的扉页每集降价文件和“身体”。

您可以在下面预览如何将新的降价文件与提取的内容组合在一起。 我认为这将使您对我们未来的范围有个好主意。 这是我们小脚本中的最后一步。 不用担心,我们将更详细地介绍它。

def compose_markdown

def compose_markdown(options={})
<<-HEREDOC
---
title: #{options[:interviewee]}
interviewee: #{options[:interviewee]}
topic_list: #{options[:title]}
tags: #{options[:tags]}
soundcloud_id: #{options[:sc_id]}
date: #{options[:date]}
episode_number: #{options[:episode_number]}
---#{options[:text]}
HEREDOC
end

我还想添加一些旧站点无法播放的技巧。 对我来说,拥有定制的,全面的标记系统至关重要。 我希望听众拥有一个深入的发现工具。 因此,我需要为每个受访者提供标签,并将子标题也分成标签。 由于仅在第一季就制作了139集,所以我不得不为网站准备一段时间,以使内容的梳理变得更加困难。 带有智能放置推荐的深度标记系统是必经之路。 这使我能够保持网站的轻巧和快速。

让我们看一下抓取网站内容的完整代码。 环顾四周,尝试找出正在发生的一切。 由于我希望您是事物的初学者,因此我避免过多地进行抽象,而在清晰性方面犯了错误。 我做了一些旨在帮助代码清晰的重构,但是当您完成本文时,我还为您留了一些肉。 毕竟,当您不仅仅阅读和玩弄一些代码时,就会进行高质量的学习。

在此过程中,我强烈建议您开始考虑如何改善自己面前的代码。 这将是本文结尾的最后任务。 我的提示:将大型方法分解为较小的方法始终是一个很好的起点。 一旦了解了代码的工作原理,就应该在重构过程中花点时间。

我已经从将一堆方法提取到专注的小型助手中开始了。 您应该可以轻松地应用从我以前的文章中所学到的关于代码气味及其重构的知识 。 如果现在您仍然无法解决这个问题,请不要担心-我们都去过那里。 只要坚持下去,某些时候事情就会开始加快点击速度。

完整代码

require 'Mechanize'
require 'Pry'
require 'date'# Helper Methods# (Extraction Methods)def extract_interviewee(detail_page)interviewee_selector = '.episode_sub_title span'detail_page.search(interviewee_selector).text.strip
enddef extract_title(detail_page)title_selector = ".episode_title"detail_page.search(title_selector).text.gsub(/[?#]/, '')
enddef extract_soundcloud_id(detail_page)sc = detail_page.iframes_with(href: /soundcloud.com/).to_ssc.scan(/\d{3,}/).first
enddef extract_shownotes_text(detail_page)shownote_selector = "#shownote_container > p"detail_page.search(shownote_selector)
enddef extract_subtitle(detail_page)subheader_selector = ".episode_sub_title"detail_page.search(subheader_selector).text
enddef extract_episode_number(episode_subtitle)number = /[#]\d*/.match(episode_subtitle)clean_episode_number(number)
end# (Utility Methods)def clean_date(episode_subtitle)string_date = /[^|]*([,])(.....)/.match(episode_subtitle).to_sDate.parse(string_date)
enddef build_tags(title, interviewee)extracted_tags = strip_pipes(title)"#{interviewee}"+ ", #{extracted_tags}"
enddef strip_pipes(text)tags = text.tr('|', ',')tags = tags.gsub(/[@?#&]/, '')tags.gsub(/[w\/]{2}/, 'with')
enddef clean_episode_number(number)number.to_s.tr('#', '')
enddef dasherize(text)text.lstrip.rstrip.tr(' ', '-')
enddef extract_data(detail_page)interviewee = extract_interviewee(detail_page)title = extract_title(detail_page)sc_id = extract_soundcloud_id(detail_page)text = extract_shownotes_text(detail_page)episode_subtitle = extract_subtitle(detail_page)episode_number = extract_episode_number(episode_subtitle)date = clean_date(episode_subtitle)tags = build_tags(title, interviewee)options = {interviewee:    interviewee,title:          title,sc_id:          sc_id,text:           text,tags:           tags,date:           date,episode_number: episode_number}
enddef compose_markdown(options={})
<<-HEREDOC
---
title: #{options[:interviewee]}
interviewee: #{options[:interviewee]}
topic_list: #{options[:title]}
tags: #{options[:tags]}
soundcloud_id: #{options[:sc_id]}
date: #{options[:date]}
episode_number: #{options[:episode_number]}
---#{options[:text]}
HEREDOC
enddef write_page(link)detail_page = link.clickextracted_data = extract_data(detail_page)markdown_text = compose_markdown(extracted_data)date = extracted_data[:date]interviewee = extracted_data[:interviewee]episode_number = extracted_data[:episode_number]File.open("#{date}-#{dasherize(interviewee)}-#{episode_number}.html.erb.md", 'w') { |file| file.write(markdown_text) }
enddef scrapelink_range = 1agent ||= Mechanize.newuntil link_range == 21page = agent.get("https://between-screens.herokuapp.com/?page=#{link_range}")link_range += 1page.links[2..8].map do |link|write_page(link)endend
endscrape

我们为什么不require "Nokogiri" ? 机械化为我们提供了所有刮削需求。 正如我们在上一篇文章中讨论的那样,Mechanize建立在Nokogiri之上,并且还允许我们提取内容。 但是,在第一篇文章中覆盖该宝石非常重要,因为我们需要在此基础上进行构建。

首先是第一件事。 在我们进入本文的代码之前,我认为有必要向您展示如何有效检查代码的每一步是否按预期工作。 正如您肯定已经注意到的那样,我在组合中添加了另一个工具。 除其他外, Pry非常方便调试。

如果将Pry.start(binding)放置在代码中的任何位置,则可以在该点检查应用程序。 您可以在应用程序中的特定位置撬入对象。 这对于一步一步地完成应用程序而不会引起您的麻烦很有帮助。 例如,让我们将其放在我们的write_page函数之后,并检查link是否符合我们的期望。

...def scrapelink_range = 1agent ||= Mechanize.newuntil link_range == 21page = agent.get("https://between-screens.herokuapp.com/?page=#{link_range}")link_range += 1page.links[2..8].map do |link|write_page(link)Pry.start(binding)endend
end...

如果您运行脚本,我们将得到类似的信息。

输出量

»$ ruby noko_scraper.rb321: def scrape322:     link_range = 1323:     agent ||= Mechanize.new324: 326:   until link_range == 21327:     page = agent.get("https://between-screens.herokuapp.com/?page=#{link_range}")328:     link_range += 1329: 330:     page.links[2..8].map do |link|331:       write_page(link)=> 332:     Pry.start(binding)333:     end334:   end335: end[1] pry(main)>

然后,当我们请求link对象时,我们可以在继续其他实现细节之前检查我们是否处在正确的轨道上。

终奌站

[2] pry(main)> link
=> #<Mechanize::Page::Link"Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values""/episodes/139">

看起来像我们需要的。 太好了,我们可以继续。 逐步遍历整个应用程序是确保您不会迷路并且真正了解其工作原理的重要实践。 我将在这里不再详细介绍Pry,因为这样做至少需要我再写一篇完整的文章。 我只能建议将其用作标准IRB外壳的替代产品。 回到我们的主要任务。

刮刀

现在您已经有机会熟悉适当的拼图,我建议我们逐一介绍它们,并在此处和此处阐明一些有趣的观点。 让我们从核心部分开始。

podcast_scraper.rb

...def write_page(link)detail_page = link.clickextracted_data = extract_data(detail_page)markdown_text = compose_markdown(extracted_data)date = extracted_data[:date]interviewee = extracted_data[:interviewee]episode_number = extracted_data[:episode_number]file_name = "#{date}-#{dasherize(interviewee)}-#{episode_number}.html.erb.md" File.open(file_name, 'w') { |file| file.write(markdown_text) }
enddef scrapelink_range = 1agent ||= Mechanize.newuntil link_range == 21page = agent.get("https://between-screens.herokuapp.com/?page=#{link_range}")link_range += 1page.links[2..8].map do |link|write_page(link)endend
end...

scrape方法会发生什么? 首先,我遍历旧播客中的每个索引页面。 我正在使用Heroku应用中的旧网址,因为新网站已经在betweenscreens.fm上在线了。 我需要翻阅20页的剧集。

我通过link_range变量对循环定界,该变量随每个循环更新。 分页就像在每个页面的URL中使用此变量一样简单。 简单有效。

def scrape

page = agent.get("https://between-screens.herokuapp.com/?page=#{link_range}")

然后,每当我要抓取一个新页面时又要抓取八个情节时,我就使用page.links来标识我们要单击的链接,并转到每个情节的详细信息页面。 我决定使用一系列链接( links[2..8] ),因为它在每个页面上都是一致的。 这也是从每个索引页面定位我需要的链接的最简单方法。 无需在这里随意使用CSS选择器。

然后,我们将详细页面的链接输入到write_page方法。 这是完成大部分工作的地方。 我们单击该链接,然后单击它,然后将其转到详细信息页面,在此我们可以开始提取其数据。 在该页面上,我们找到了为新网站撰写新的降价集所需的所有信息。

def write_page

extracted_data = extract_data(detail_page)

def extract_data

def extract_data(detail_page)interviewee = extract_interviewee(detail_page)title = extract_title(detail_page)sc_id = extract_soundcloud_id(detail_page)text = extract_shownotes_text(detail_page)episode_subtitle = extract_subtitle(detail_page)episode_number = extract_episode_number(episode_subtitle)date = clean_date(episode_subtitle)tags = build_tags(title, interviewee)options = {interviewee:    interviewee,title:          title,sc_id:          sc_id,text:           text,tags:           tags,date:           date,episode_number: episode_number}
end

正如您在上面看到的,我们采用了detail_page并对其应用了一系列提取方法。 我们提取intervieweetitlesc_idtextepisode_titleepisode_number 。 我重构了一系列专注于这些提取职责的辅助方法。 让我们快速看一下它们:

辅助方法

提取方法

之所以提取这些帮助程序是因为它使我总体上可以使用较小的方法。 封装他们的行为也很重要。 该代码也阅读得更好。 他们中的大多数人都将detail_page作为参数,并提取一些我们中间人帖子所需的特定数据。

def extract_interviewee(detail_page)interviewee_selector = '.episode_sub_title span'detail_page.search(interviewee_selector).text.strip
end

我们在页面上搜索特定的选择器,并获得没有多余空格的文本。

def extract_title(detail_page)title_selector = ".episode_title"detail_page.search(title_selector).text.gsub(/[?#]/, '')
end

我们拿了标题并删除了?#因为它们与我们剧集帖子中的头条内容搭配得不好。 以下是有关前端问题的更多信息。

def extract_soundcloud_id(detail_page)sc = detail_page.iframes_with(href: /soundcloud.com/).to_ssc.scan(/\d{3,}/).first
end

在这里,我们需要更加努力地提取托管轨道的SoundCloud ID。 首先,我们需要带有soundcloud.comhref的Mechanize iframe,并将其设置为扫描字符串...

"[#<Mechanize::Page::Frame\n nil\n \"https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/221003494&amp;auto_play=false&amp;hide_related=false&amp;show_comments=false&amp;show_user=true&amp;show_reposts=false&amp;visual=true\">\n]"

然后将正则表达式与其音轨ID的数字匹配-我们的soundcloud_id "221003494"

def extract_shownotes_text(detail_page)shownote_selector = "#shownote_container > p"detail_page.search(shownote_selector)
end

提取演出笔记也非常简单。 我们只需要在详细信息页面中查找展示笔记的段落即可。 这里没有惊喜。

def extract_subtitle(detail_page)subheader_selector = ".episode_sub_title"detail_page.search(subheader_selector).text
end

副标题也是如此,只是它只是从中干净地提取剧集编号的一种准备。

def extract_episode_number(episode_subtitle)number = /[#]\d*/.match(episode_subtitle)clean_episode_number(number)
end

在这里,我们需要另一轮正则表达式。 让我们看看应用正则表达式之前和之后。

Episode_subtitle

" João Ferreira  | 12  Minutes |  Aug 26, 2015 | Episode #139  "

"#139"

再走一步,直到我们得到一个干净的数字。

def clean_episode_number(number)number.to_s.tr('#', '')
end

我们用井号#删除该数字。 Voilà,我们也提取了第一集139 。 我建议我们在将所有实用程序组合在一起之前,先看看其他实用程序方法。

实用方法

完成所有提取工作后,我们需要做一些清理工作。 我们已经可以开始准备构成降价的数据了。 例如,我将episode_subtitle切得episode_subtitle一些,以得到一个干净的日期,并使用build_tags方法构建tags

def clean_date

def clean_date(episode_subtitle)string_date = /[^|]*([,])(.....)/.match(episode_subtitle).to_sDate.parse(string_date)
end

我们运行另一个正则表达式,查找日期如下: " Aug 26, 2015" 。 如您所见,这还不是很有帮助。 从字幕获得的string_date ,我们需要创建一个真实的Date对象。 否则,创建中间人帖子将毫无用处。

string_date

"  Aug 26, 2015"

因此,我们采用该字符串并执行Date.parse 。 结果看起来更有希望。

日期

2015-08-26

def build_tags

def build_tags(title, interviewee)extracted_tags = strip_pipes(title)"#{interviewee}"+ ", #{extracted_tags}"
end

这将使用我们在extract_data方法中建立的titleinterviewee者,并删除所有管道字符和垃圾内容。 我们用逗号@ ,?代替竖线字符?#&与一个空字符串,最后要注意with的缩写。

def strip_pipes

def strip_pipes(text)tags = text.tr('|', ',')tags = tags.gsub(/[@?#&]/, '')tags.gsub(/[w\/]{2}/, 'with')
end

最后,我们还要在标签列表中包括受访者的姓名,并用逗号分隔每个标签。

之前

"Masters @ Work | Subvisual | Deadlines | Design personality | Design problems | Team | Pushing envelopes | Delightful experiences | Perfecting details | Company values"

"João Ferreira, Masters  Work , Subvisual , Deadlines , Design personality , Design problems , Team , Pushing envelopes , Delightful experiences , Perfecting details , Company values"

这些标签中的每一个最终都将成为指向该主题的帖子集合的链接。 所有这些都发生在extract_data方法内部。 让我们再看一下我们的位置:

def extract_data

def extract_data(detail_page)interviewee = extract_interviewee(detail_page)title = extract_title(detail_page)sc_id = extract_soundcloud_id(detail_page)text = extract_shownotes_text(detail_page)episode_subtitle = extract_subtitle(detail_page)episode_number = extract_episode_number(episode_subtitle)date = clean_date(episode_subtitle)tags = build_tags(title, interviewee)options = {interviewee:    interviewee,title:          title,sc_id:          sc_id,text:           text,tags:           tags,date:           date,episode_number: episode_number}
end

剩下要做的就是返回一个包含我们提取的数据的选项哈希。 我们可以将此哈希值输入compose_markdown方法,该方法可以将我们的数据准备好写为新站点所需的文件。

写文章

def compose_markdown

def compose_markdown(options={})
<<-HEREDOC
---
title: #{options[:interviewee]}
interviewee: #{options[:interviewee]}
topic_list: #{options[:title]}
tags: #{options[:tags]}
soundcloud_id: #{options[:sc_id]}
date: #{options[:date]}
episode_number: #{options[:episode_number]}
---#{options[:text]}
HEREDOC
end

为了在我的Middleman网站上发布播客节目,我选择重新调整其博客系统的用途。 我没有创建“纯”博客文章,而是为我的剧集创建了显示注释,这些事件通过iframe显示了SoundCloud托管的剧集。 在索引网站上,我只显示该iframe以及标题和内容。

我需要的工作格式由称为前题的东西组成。 这基本上是我的静态网站的键/值存储。 它取代了我以前的Sinatra网站上的数据库需求。

诸如受访者姓名,日期,SoundCloud曲目ID,情节编号等数据在情节文件顶部位于三个破折号( --- )之间。 以下是每集的内容-问题,链接,赞助商之类的东西。

前事

---
key: value
key: value
key: value
key: value
---Episode content goes here.

compose_markdown方法中,我使用HEREDOC在循环播放的每个情节HEREDOC文件及其HEREDOC进行组合。 从选项哈希中,我们为该方法提供数据,然后提取在extract_data helper方法中收集的所有数据。

def compose_markdown

...<<-HEREDOC
---
title: #{options[:interviewee]}
interviewee: #{options[:interviewee]}
topic_list: #{options[:title]}
tags: #{options[:tags]}
soundcloud_id: #{options[:sc_id]}
date: #{options[:date]}
episode_number: #{options[:episode_number]}
---#{options[:text]}
HEREDOC...

这是在那里播出新播客的蓝图。 这就是我们的目的。 也许您想知道这种特定的语法: #{options[:interviewee]} 。 我像往常一样使用字符串进行插值,但是由于我已经在<<-HEREDOC ,因此可以<<-HEREDOC双引号。

只是为了调整自己的方向,我们仍然处于循环中,在write_page函数内,每个单击到链接的详细信息页面的链接都带有单个情节的注释。 接下来发生的事情是准备将此蓝图写入文件系统。 换句话说,我们通过提供文件名和组成的markdown_text创建实际情节。

对于最后一步,我们只需要准备以下内容:日期,受访者姓名和剧集编号。 加上markdown_text当然是我们刚从compose_markdown

def write_page

...markdown_text = compose_markdown(extracted_data)
date = extracted_data[:date]
interviewee = extracted_data[:interviewee]
episode_number = extracted_data[:episode_number]file_name = "#{date}-#{dasherize(interviewee)}-#{episode_number}.html.erb.md" ...

然后,我们只需要使用file_namemarkdown_text并写入文件。

def write_page

...File.open(file_name, 'w') { |file| file.write(markdown_text) }...

让我们也分解一下。 对于每个帖子,我都需要一种特定的格式:类似于2016-10-25-Avdi-Grimm-120 。 我想写出以日期开头的文件,其中包括受访者的姓名和剧集编号。

为了匹配格式中间人预计,新的职位,我需要把受访者的名字,并把它通过我的辅助方法dasherize我的名字,从Avdi GrimmAvdi-Grimm 。 没什么魔术,但是值得一看:

def dasherize

def dasherize(text)text.lstrip.rstrip.tr(' ', '-')
end

它从我们为被访者姓名抓取的文本中删除了空格,并用破折号替换了Avdi和Grimm之间的空格。 文件名的其余部分在字符串本身中"date-interviewee-name-episodenumber"划线: "date-interviewee-name-episodenumber"

def write_page

..."#{date}-#{dasherize(interviewee)}-#{episode_number}.html.erb.md"...

由于提取的内容直接来自HTML网站,因此我不能简单地使用.md.markdown作为文件扩展名。 我决定使用.html.erb.md 。 对于以后撰写而无需抓取的情节,我可以.html.erb部分,只需要.md

完成此步骤后, scrape函数中的循环结束,我们应该有一个看起来像这样的情节:

2014-12-01-Avdi-Grimm-1.html.erb.md

---
title: Avdi Grimm
interviewee: Avdi Grimm
topic_list: What is Rake | Origins | Jim Weirich | Common use cases | Advantages of Rake
tags: Avdi Grimm, What is Rake , Origins , Jim Weirich , Common use cases , Advantages of Rake
soundcloud_id: 179619755
date: 2014-12-01
episode_number: 1
---Questions:
- What is Rake?
- What can you tell us about the origins of Rake?
- What can you tell us about Jim Weihrich?
- What are the most common use cases for Rake?
- What are the most notable advantages of Rake?Links:
In">http://www.youtube.com/watch?v=2ZHJSrF52bc">In memory of the great Jim Weirich
Rake">https://github.com/jimweirich/rake">Rake on GitHub
Jim">https://github.com/jimweirich">Jim Weirich on GitHub
Basic">http://www.youtube.com/watch?v=AFPWDzHWjEY">Basic Rake talk by Jim Weirich
Power">http://www.youtube.com/watch?v=KaEqZtulOus">Power Rake talk by Jim Weirich
Learn">http://devblog.avdi.org/2014/04/30/learn-advanced-rake-in-7-episodes/">Learn advanced Rake in 7 episodes - from Avdi Grimm ( free )
Avdi">http://about.avdi.org/">Avdi Grimm
Avdi Grimm’s screencasts: Ruby">http://www.rubytapas.com/">Ruby Tapas
Ruby">http://devchat.tv/ruby-rogues/">Ruby Rogues podcast with Avdi Grimm
Great ebook: Rake">http://www.amazon.com/Rake-Management-Essentials-Andrey-Koleshko/dp/1783280778">Rake Task Management Essentials fromhttps://twitter.com/ka8725"> Andrey Koleshko

当然,此抓取工具将从最后一集开始,一直循环到第一集。 出于演示目的,第1集与任何第1集一样好。 您可以在最前面看到我们提取的数据。

所有这些以前都已锁定在我的Sinatra应用程序的数据库中-剧集编号,日期,受访者姓名等。 现在,我们已经准备好成为我的新静态Middleman网站的一部分。 两个三横线( --- )下方的所有内容都是显示注释中的文字:主要是问题和链接。

最后的想法

我们完成了。 我的新播客已经启动并正在运行。 我很高兴花时间从头开始重新设计它。 现在发布新剧集要酷得多。 对于用户来说,发现新内容也应该更加顺畅。

正如我之前提到的,这是您应该进入代码编辑器以获得一些乐趣的时候。 采取这段代码,并与之搏斗。 尝试找到使它更简单的方法。 有一些机会可以重构代码。

总体而言,我希望这个小例子能使您对使用新的Web抓取扒条能做什么有个好主意。 当然,您可以解决更复杂的挑战-我相信利用这些技能甚至可以创造许多小型商业机会。

但是,与往常一样,一次只迈出一步,如果事情没有立即点击,也不要感到沮丧。 这不仅对大多数人来说是正常的,而且是可以预料的。 这是旅程的一部分。 刮刮乐!

翻译自: https://code.tutsplus.com/articles/building-your-first-web-scraper-part-3--cms-27599

构建您的第一个Web爬网程序,第3部分相关推荐

  1. 构建您的第一个Web爬网程序,第2部分

    在本教程中,您将学习如何使用Mechanize单击链接,填写表单和上传文件. 您还将学习如何切片机械化页面对象,以及如何自动执行Google搜索并保存其结果. 主题 单页与分页 机械化 代理商 页 N ...

  2. vs azure web_在Azure中迁移和自动化Chrome Web爬网程序的指南。

    vs azure web Webscraping as a required skill for many data-science related jobs is becoming increasi ...

  3. r语言r-shiny_使用Shiny和R构建您的第一个Web应用程序仪表板

    r语言r-shiny by AMR 通过AMR 使用Shiny和R构建您的第一个Web应用程序仪表板 (Build your first web app dashboard using Shiny a ...

  4. 【ASP.NET教程-WP教程15】ASP.NET Web Pages - C# 和 VB 实例简单而强大的开发框架,可用于构建动态的、基于Web的应用程序。它提供了一种轻量级的方式来创建和管理网页

    ASP.NET Web Pages - C# 和 VB 实例 ASP.NET Web Pages 是一种简单而强大的开发框架,可用于构建动态的.基于Web的应用程序.它提供了一种轻量级的方式来创建和管 ...

  5. python web应用_为您的应用选择最佳的Python Web爬网库

    python web应用 Living in today's world, we are surrounded by different data all around us. The ability ...

  6. python爬虫如何运行在web_Python Web爬网-使用爬虫进行测试

    本章介绍了如何在Python中使用Web抓取工具执行测试. 介绍 在大型Web项目中,会定期执行网站后端的自动化测试,但经常会跳过前端测试.这背后的主要原因是网站的编程就像各种标记和编程语言的网络一样 ...

  7. 做事用人 用人做事_做事:构建我的第一个Web应用程序的经验教训

    做事用人 用人做事 On the 5th of June, 2020, after almost two weeks of (re)learning javascript, fixing bugs, ...

  8. SharePoint Framework 构建你的第一个web部件(三)

    博客地址:http://blog.csdn.net/FoxDave 本篇接上一讲,我们一起来看一下如何部署和测试本地开发的web部件. 在SharePoint中预览web部件 SharePoint ...

  9. 使用BeautifulSoup的Python Web爬网教程

    When performing data science tasks, it's common to want to use data found on the internet. You'll us ...

  10. python爬取行业数据_用Python进行Web爬取数据

    介绍 我们拥有的数据太少,无法建立机器学习模型.我们需要更多数据! 如果这句话听起来很熟悉,那么你并不孤单!希望获得更多数据来训练我们的机器学习模型是一个一直困扰人们的问题.我们无法在数据科学项目中获 ...

最新文章

  1. 450g吐司烘烤温度_教你一手如何判断吐司面包是否烤熟
  2. python3 image与 图像io互转
  3. leetcode--5. 最长回文子串
  4. linux 取出字符中数字,使用awk提取字符串中的数字或字母
  5. iOS开发必读-GitHub 上Top100 的 Objective-C 项目
  6. python基于SMTP发送邮件(qq邮箱)
  7. 允许使用抽象类类型 isearchboxinfo 的对象_Java面向对象之final、abstract抽象、和变量生命周期...
  8. Python简单实现图书管理系统
  9. VirtualBox安装Windows和CentOS虚拟机
  10. 华为海思智能手机处理器及其参数对比
  11. 安全测试——SQL注入
  12. 阿里 卫哲谈阿里人力招聘价值观
  13. spark视频-第二期:Shark、SparkSQL
  14. tensorflow中将标注文件写到train.txt, test.txt,trainval.txt中
  15. 何谓OTA(Over-the-air programming)?
  16. 系统之家xp服务器系统怎么安装,windowsxp系统之家系统详细安装步骤
  17. 分布式限流的解决方案
  18. 基于 Mesh 的统一路由在海外业务的实践
  19. 新浪财经沪深300指数期权和商品期权行情接口
  20. Arena仿真-基于超市排队的建模分析

热门文章

  1. 开帖记录每天工作学习日常
  2. 快上车!薅腾讯羊毛!
  3. 'sa'登录失败解决方案大全
  4. python 随机生成6位数字+字母的密码
  5. 关于ShadowMap中Shadow acne现象的解释
  6. 教你电脑微信多开方法,超级简单_多啦咪
  7. OKR 如何转变你的绩效管理策略
  8. 若依源码分析(7)——岗位管理
  9. word 计算机内存不足,word文档保存提示内存不足怎么办
  10. 高程数据下载——DLR_SRTM_说明