实验项目要求
1.核心需求:
1)选取3-5个代表性的新闻网站(比如新浪新闻、网易新闻等,或者某个垂直领域权威性的网站比如经济领域的雪球财经、东方财富等,或者体育领域的腾讯体育、虎扑体育等等)建立爬虫,针对不同网站的新闻页面进行分析,爬取出编码、标题、作者、时间、关键词、摘要、内容、来源等结构化信息,存储在数据库中。
2) 建立网站提供对爬取内容的分项全文搜索,给出所查关键词的时间热度分析。
2.必须采用Node.JS实现网络爬虫
3.必须采用Node.JS实现查询网站后端,HTML+JS实现前端(尽量不要使用任何前后端框架)
- [√] 爬取标题等结构化信息,存储在数据库中
- [√] 建立网站提供分项全文搜索
- [?] 给出所查关键词的时间热度分析
- [√] 采用Node.JS实现网络爬虫
- [√] 采用Node.JS实现查询网站后端
- [√] HTML+JS实现前端
终极要求(4/27改)
1、完成对数据库中爬取数据内容或者标题的搜索功能,搜索结果以表格的形式展示在前端页面中(√)
2、完成对搜索内容的时间热度分析,展示某一关键词的条数(形式可以发挥)(?)
3、网站页面设计简洁美观(√)
4、详细描述目标网站的分析过程;详细描述爬虫整体结构、使用的工具包、数据库设计;详细描述搜索网站前后端的设计;图文展示实现的效果(√)
提示
var schedule = require('node-schedule') //设置定时爬虫
var myIconv = require(‘iconv-lite’) //编码转换 GB2312到UTF-8
var fs = require(‘fs’); //保存到本地文件
var mysql = require(‘mysql’); //保存到mysql数据库
npm install elasticsearch //可以用elasticsearch构建爬取数据的索引
一些可以应用于爬虫的things:
- 利用数据库存储爬取的数据(MySQL)
- 爬取新闻页面之前先查询数据库,是否该url已经爬取过了
- 使用node-schedule模块,设置定时工作
- 用网页发送请求到后端进行查询
- 用express构建网站,访问mysql
- 用表格显示所查询的结果
- something else(如,分析有多个种子页面的情况下设计爬虫)
具体实现过程(一)
我的第一个爬虫(简陋的雪球)
- 分析种子页面,找到要爬取的a链接
- 进入新闻页面,找出所爬取的源代码
- 得到思路:读取种子页面、分析所有新闻链接、爬取新闻链接中的内容、分析内容,解析出结构化数据、将结构化数据保存到本地,再将数据保存到数据库中,通过构建网页清晰地呈现
(PS:选取了“雪球”,主要是因为它的代码比较简单,然后大致的框架仍是基于老师的教学代码)
- 分析网站源代码结构,通过逐一检查,发现:所有的帖子都是在class=AnonymousHome_a__placeholder_3RZ的目录下
- 进一步分析目录下的a链接中的内容,发现,种子页面的网址(seedURL)+ href = 即为二级网站的网址(url)
- 找到二级网站中,标题、摘要、来源、日期、作者对应的html语言(后期定稿时截图,故有些细节不完全一致)
初稿
(写在本地)
var source_name = "雪球网";
var myEncoding = "utf-8";
var seedURL = 'https://xueqiu.com';
var seedURL_format = "$('.AnonymousHome_a__placeholder_3RZ')";
var keywords_format = " $('meta[name=\"keywords\"]').eq(0).attr(\"content\")";
var title_format = "$('article_bd_title').text()";
var desc_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";
var source_format = "$('source').text()";
var date_format = "$('time').text()";
var author_format = "$('data_screenname').text()";
var fs = require('fs');
var myRequest = require('request')
var myCheerio = require('cheerio')
var myIconv = require('iconv-lite')
require('date-utils');
var headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36'
}
function request(url, callback) {
var options = {
url: url,
encoding: null,
headers: headers,
timeout: 10000
}
myRequest(options, callback)
}
request(seedURL, function(err, res, body) {
var html = myIconv.decode(body, myEncoding);
var $ = myCheerio.load(html, { decodeEntities: true });
var seedurl_news;
try {
seedurl_news = eval(seedURL_format);
} catch (e) { console.log('url列表所处的html块识别出错:' + e) };
seedurl_news.each(function(i, e) {
var myURL = "";
try {
var href = "";
href = $(e).attr("href");
if (typeof(href) == "undefined") {
return true;
}
myURL = seedURL + href;
} catch (e) { console.log('识别种子页面中的新闻链接出错:' + e) }
newsGet(myURL);
});
});
function newsGet(myURL) {
request(myURL, function(err, res, body) {
var myhtml = myIconv.decode(body, myEncoding);
var $ = myCheerio.load(myhtml, { decodeEntities: true });
console.log("转码读取成功:" + myURL);
var fetch = {};
fetch.url = myURL;
fetch.title = "";
fetch.source_name = source_name;
fetch.source_encoding = myEncoding;
fetch.date = "";
if (keywords_format == "") fetch.keywords = source_name;
else fetch.keywords = eval(keywords_format);
if (title_format == "") fetch.title = ""
else fetch.title = eval(title_format);
if (desc_format == "") fetch.desc = fetch.title;
else fetch.desc = eval(desc_format).replace("\r\n", "");
if (date_format == "") fetch.date = ""
else fetch.date = eval(date_format);
if (author_format == "") fetch.author = source_name;
else fetch.author = eval(author_format);
if (source_format == "") fetch.source = fetch.source_name;
else fetch.source = eval(source_format).replace("\r\n", "");
console.log('date: ' + fetch.date);
console.log(myURL);
var filename = source_name + "_" + myURL.substr(myURL.lastIndexOf('/') + 1) + ".json";
fs.writeFileSync(filename, JSON.stringify(fetch));
});
}
代码解析
- 具体实现步骤:定义要访问的网站;引入必要的模块;定义新闻页面里具体的元素的读取方式;定义哪些url可以作为新闻页面(使用正则表达式)
- 其中,例如
var url_reg = /\/(\d{4})\/(\d{2})-(\d{2})\/(\d{7}).shtml/; var regExp = /((\d{4}|\d{2})(\-|\/|\.)\d{1,2}\3\d{1,2})|(\d{4}年\d{1,2}月\d{1,2}日)/
使用了正则表达式,详见 - 构造了一个模仿浏览器的request(其实request包npm上有,老师给了就直接用了)
- 在request函数中读取页面,解析出种子页面中所有的class=AnonymousHome_a__placeholder_3RZ链接
- 通过each语句,遍历种子页面中的所有class=AnonymousHome_a__placeholder_3RZ链接,并通过规整化所有链接,(后面爬取的a链接时,需要通过正则表达式来判断,如果符合我们设定的新闻URL的正则表达式才爬出)
- 再定义了newsGet函数,读取具体的新闻页面(也就是俗称的二级网站),并构造一个空的fetch对象用于存储数据(里面调用的request函数和种子页面的调用雷同)
- 将读取的新闻页面中需要的元素保存到fetch对象中
- 最后,将fetch对象保存在文件中(后面mysql中的fetch即为此物)
- 执行该文件,即可创建出多个符合条件的新闻文件
- cheerio是一个Node.JS的模块库,可以从HTML的片段中构建DOM结构,然后提供像jQuery一样的CSS选择器查询,通过npm install cheerio安装该模块
- request也是一个Node.JS的模块库,可以轻松地完成HTTP请求,同理使用npm install request安装
- 通过npm官网查看每个模块的相关资料
cheerio
request
(ps:此处npm安装略,官网下载) - url是指一个网址,callback就是一个回调函数
- var定义全局变量;let定义局部变量
- encoding:使用null时,传递二进制数据;其他任何值将传递给toString;此处我们需要获得二进制数据
- headers:HTTP头,一般设为null
- 必要时,为了防止对方屏蔽我们爬虫。可以伪装成网页
var headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36' }
- decode 将缓冲区编码转换为js字符串
- try-catch
try { //在这里运行代码 抛出错误 } catch(err) { //在这里处理错误 }
后半句相当于(如下代码为基础学习时所写)
if (err || res.statusCode != 200) {
console.error(err);
console.error(res.statusCode);
return;
}
- eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。此处计算的是含有a标签的链接;后面是为了将源代码中的属性交给定义的变量
- each的参数function(index,element)
- toLowerCase() 方法用于把字符串转换为小写。
- indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。代码中是为了判断以’http://'和’https://'开头的链接(若以//开头,要自行加入http:)
- substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符,语法:stringObject.substr(start,length)
- lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
- 创建date对象——var myDate=new Date()//Date 对象会自动把当前日期和时间保存为其初始值。
- exec() 方法用于检索字符串中的正则表达式的匹配。领用此函数检查正则表达式
- replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
- MySQL的一些语法:
mysql_query() 函数执行一条 MySQL 查询。语法:mysql_query(query,connection)其中,query必需,规定要发送的SQL查询,查询字符串不能以分号结束;connection可选,规定SQL连接标识符,如果未规定,则使用上一个打开的链接 - 关于Express脚手架的搭建:
在配置环境的过程中发现,要实现在前端进行关键词的搜索,只需要更改为mysql.js中数据库的名字(前提是完成一次脚手架的搭建),即可完成简易地搭建
运行结果
对照每一个爬出的结果,title、date、author、source为空
订正部分
var source_format = "$('.source').text()";
var date_format = "$('.time').text()";
var author_format = "$('.data_screenname').text()";
错误原因
- id=“pubtime_baidu” 在js中写为#pubtime_baidu
- class=“left_zw” 在js中写为.left_zw;
- 另外,关于网址为什么没有最后的“/”,连接seedURL和href的时候也会自动加上/
polish(仅显示修改部分)
(存入数据库)
var mysql = require('./mysql.js');
seedget();
function seedget() {
request(seedURL, function(err, res, body) {
var html = myIconv.decode(body, myEncoding);
var $ = myCheerio.load(html, { decodeEntities: true });
var seedurl_news;
try {
seedurl_news = eval(seedURL_format);
} catch (e) { console.log('url列表所处的html块识别出错:' + e) };
seedurl_news.each(function(i, e) {
var myURL = "";
try {
var href = "";
href = $(e).attr("href");
if (href == undefined) return true;
myURL = seedURL + href;
} catch (e) { console.log('识别种子页面中的新闻链接出错:' + e) }
var fetch_url_Sql = 'select url from fetches where url=?';
var fetch_url_Sql_Params = [myURL];
mysql.query(fetch_url_Sql, fetch_url_Sql_Params, function(qerr, vals, fields) {
if (vals.length > 0) {
console.log('URL duplicate!')
} else newsGet(myURL);
});
});
});
};
function newsGet(myURL) {
request(myURL, function(err, res, body) {
var fetchAddSql = 'INSERT INTO fetches(url,source_name,source_encoding,title,' +
'keywords,author,date) VALUES(?,?,?,?,?,?,?,?,?)';
var fetchAddSql_Params = [fetch.url, fetch.source_name, fetch.source_encoding,
fetch.title, fetch.keywords, fetch.author, fetch.date];
mysql.query(fetchAddSql, fetchAddSql_Params, function(qerr, vals, fields) {
if (qerr) {
console.log(qerr);
}
});
});
}
//借助MySQL进行存储,代码运行结果显示,sql能够显示所爬取的信息,但是在MySQL中无法找到对应的爬取内容,在助教的指导下设置断点查看数据:(
重新建立了一个crawl2后,发现其中的fetches为空,且程序会持续running,无法自动停下
后来数据结构代码也遇到了同样的问题,好像是因为误删了vscode的配置,呜呜呜,环境配置一直都好迷啊
代码改进中……
最终代码
var source_name = "雪球网";
var myEncoding = "utf-8";
var seedURL = 'https://xueqiu.com';
var seedURL_format = "$('.AnonymousHome_a__placeholder_3RZ')";
var keywords_format = " $('meta[name=\"keywords\"]').eq(0).attr(\"content\")";
var title_format = "$('title').text()";
var desc_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";
var source_format = "$('.source').text()";
var date_format = "$('.time').text()";
var author_format = "$('.data_screenname').text()";
var fs = require('fs');
var myRequest = require('request');
var myCheerio = require('cheerio');
var myIconv = require('iconv-lite');
require('date-utils');
var mysql = require('./mysql.js');
var headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36'
}
function request(url, callback) {
var options = {
url: url,
encoding: null,
headers: headers,
timeout: 10000 //
}
myRequest(options, callback)
};
seedget();
function seedget() {
request(seedURL, function(err, res, body) {
var html = myIconv.decode(body, myEncoding);
var $ = myCheerio.load(html, { decodeEntities: true });
var seedurl_news;
try {
seedurl_news = eval(seedURL_format);
} catch (e) { console.log('url列表所处的html块识别出错:' + e) };
seedurl_news.each(function(i, e) {
var myURL = "";
try {
var href = "";
href = $(e).attr("href");
if (href == undefined) return true;
myURL = seedURL + href;
} catch (e) { console.log('识别种子页面中的新闻链接出错:' + e) }
var fetch_url_Sql = 'select url from fetches where url=?';
var fetch_url_Sql_Params = [myURL];
mysql.query(fetch_url_Sql, fetch_url_Sql_Params, function(qerr, vals, fields) {
if (vals.length > 0) {
console.log('URL duplicate!')
} else newsGet(myURL);
});
});
});
};
function newsGet(myURL) {
request(myURL, function(err, res, body) {
var myhtml = myIconv.decode(body, myEncoding);
var $ = myCheerio.load(myhtml, { decodeEntities: true });
console.log("转码读取成功:" + myURL);
var fetch = {};
fetch.title = "";
fetch.url = myURL;
fetch.source_name = source_name;
fetch.source_encoding = myEncoding;
fetch.date = "";
if (keywords_format == "") fetch.keywords = source_name;
else fetch.keywords = eval(keywords_format);
if (title_format == "") fetch.title = ""
else fetch.title = eval(title_format);
if (date_format == "") fetch.date = ""
else fetch.date = eval(date_format);
console.log('date: ' + fetch.date);
if (author_format == "") fetch.author = source_name;
else fetch.author = eval(author_format);
if (source_format == "") fetch.source = fetch.source_name;
else fetch.source = eval(source_format).replace("\r\n", "");
if (desc_format == "") fetch.desc = fetch.title;
else fetch.desc = eval(desc_format).replace("\r\n", "");
var fetchAddSql = 'INSERT INTO fetches(title,url,source_name,source_encoding,' +
'keywords,author) VALUES(?,?,?,?,?,?)';
var fetchAddSql_Params = [fetch.title, fetch.url, fetch.source_name, fetch.source_encoding, fetch.keywords, fetch.author];
mysql.query(fetchAddSql, fetchAddSql_Params, function(qerr, vals, fields) {
if (qerr) {
console.log(qerr);
}
});
});
}
运行结果
(PS:因为是帖子,title包括了回复的内容,有些累赘,将在下一次的代码中尝试删减不要的成分,而且该代码貌似不能自动停止搜索,我也是后来同学提醒才知道)
在老师的提示下搭建express脚手架
脚手架搭建
创建了一个search_site文件,然后在其中的index.js中写入自己的代码;在public中创建一个search.html网页前端,并在该文件中添加好对应的音频和图片资料。(后一个爬虫的呈现)
最后结果
数据总量改进(4/27改)
var seedURL_format = "$('a')";
var url_reg = /\/(\d{10})\/(\d{9})/;
说明:因为只是爬取数据的数量问题,故没有展示前端呈现的模样,最完整的前端在下一个程序……
内容小结
虽然爬取的网页有限,而且由于网页本身的限制,爬取的内容比较冗余,但至少是向前迈进了一小步,每一次小小的成功都会让我倍感鼓舞,并继续探索,然后再不断进步。
具体实现过程(二)
我的第二个爬虫(完整的东方财富网)
代码
var fs = require('fs');
var myRequest = require('request');
var myCheerio = require('cheerio');
var myIconv = require('iconv-lite');
require('date-utils');
var mysql = require('./mysql.js');
var sourc_name = "东方财富网";
var myEncoding = "utf-8";
var seedURL = 'https://www.eastmoney.com/';
var seedURL_format = "$('a')";
var keywords_format = " $('meta[name=\"keywords\"]').eq(0).attr(\"content\")";
var title_format = "$('title').text()";
var date_format ="";// "$('.time').text()";
//var author_format = "$('#editor_baidu').text()";编辑名为代号,没有意义
var content_format = "$('#ContentBody').text()";
var desc_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";
var source_format = "$('.em_media').text()";
var url_reg = /\/(\d{18}).html/;
//var regExp = /((\d{4}|\d{2})(\-|\/|\.)\d{1,2}\3\d{1,2})|(\d{4}年\d{1,2}月\d{1,2}日)/
//防止网站屏蔽我们的爬虫
var headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36'
}
//request模块异步fetch url
function request(url, callback) {
var options = {
url: url,
encoding: null,
//proxy: 'http://x.x.x.x:8080',
headers: headers,
timeout: 10000 //
}
myRequest(options, callback)
};
seedget();
function seedget() {
request(seedURL, function(err, res, body) { //读取种子页面
// try {
//用iconv转换编码
var html = myIconv.decode(body, myEncoding);
//console.log(html);
//准备用cheerio解析html
var $ = myCheerio.load(html, { decodeEntities: true });
// } catch (e) { console.log('读种子页面并转码出错:' + e) };
var seedurl_news;
try {
seedurl_news = eval(seedURL_format);
} catch (e) { console.log('url列表所处的html块识别出错:' + e) };
seedurl_news.each(function(i, e) { //遍历种子页面里所有的a链接
var myURL = "";
try {
//得到具体新闻url
var href = "";
href = $(e).attr("href");
if (href == undefined) return;
if (href.toLowerCase().indexOf('http://') >= 0 || href.toLowerCase().indexOf('https://') >= 0) myURL = href; //http://开头的或者https://开头
else if (href.startsWith('//')) myURL = 'http:' + href; 开头的
else myURL = seedURL.substr(0, seedURL.lastIndexOf('/') + 1) + href; //其他
} catch (e) { console.log('识别种子页面中的新闻链接出错:' + e) }
if (!url_reg.test(myURL)) return; //检验是否符合新闻url的正则表达式
//console.log(myURL);
var fetch_url_Sql = 'select url from fetches where url=?';
var fetch_url_Sql_Params = [myURL];
mysql.query(fetch_url_Sql, fetch_url_Sql_Params, function(qerr, vals, fields) {
if (vals.length > 0) {
console.log('URL duplicate!')
} else newsGet(myURL); //读取新闻页面
});
});
});
};
function newsGet(myURL) { //读取新闻页面
request(myURL, function(err, res, body) { //读取新闻页面
//try {
var html_news = myIconv.decode(body, myEncoding); //用iconv转换编码
//console.log(html_news);
//准备用cheerio解析html_news
var $ = myCheerio.load(html_news, { decodeEntities: true });
myhtml = html_news;
//} catch (e) { console.log('读新闻页面并转码出错:' + e);};
console.log("转码读取成功:" + myURL);
//动态执行format字符串,构建json对象准备写入文件或数据库
var fetch = {};
fetch.title = "";
fetch.content = "";
fetch.publish_date = (new Date()).toFormat("YYYY-MM-DD");
//fetch.html = myhtml;
fetch.url = myURL;
fetch.source_name = source_name;
fetch.source_encoding = myEncoding; //编码
fetch.crawltime = new Date();
if (keywords_format == "") fetch.keywords = source_name; // eval(keywords_format); //没有关键词就用sourcename
else fetch.keywords = eval(keywords_format);
if (title_format == "") fetch.title = ""
else fetch.title = eval(title_format); //标题
if (date_format != "") fetch.publish_date = eval(date_format); //刊登日期
console.log('date: ' + fetch.publish_date);
/* {fetch.publish_date = regExp.exec(fetch.publish_date)[0];
fetch.publish_date = fetch.publish_date.replace('年', '-')
fetch.publish_date = fetch.publish_date.replace('月', '-')
fetch.publish_date = fetch.publish_date.replace('日', '')
fetch.publish_date = new Date(fetch.publish_date).toFormat("YYYY-MM-DD");}
*/
/* if (author_format == "") fetch.author = source_name; //eval(author_format); //作者
else fetch.author = eval(author_format);
*/
if (content_format == "") fetch.content = "";
else fetch.content = eval(content_format).replace("\r\n" + fetch.author, ""); //内容,是否要去掉作者信息自行决定
if (source_format == "") fetch.source = fetch.source_name;
else fetch.source = eval(source_format).replace("\r\n", ""); //来源
if (desc_format == "") fetch.desc = fetch.title;
else fetch.desc = eval(desc_format).replace("\r\n", ""); //摘要
/* var filename = source_name + "_" + (new Date()).toFormat("YYYY-MM-DD") +
"_" + myURL.substr(myURL.lastIndexOf('/') + 1) + ".json";
// 存储json
fs.writeFileSync(filename, JSON.stringify(fetch));
*/
var fetchAddSql = 'INSERT INTO fetches(url,source_name,source_encoding,title,' +
'keywords,publish_date,crawltime,content) VALUES(?,?,?,?,?,?,?,?)';
var fetchAddSql_Params = [fetch.url, fetch.source_name, fetch.source_encoding,
fetch.title, fetch.keywords,fetch.publish_date,
fetch.crawltime.toFormat("YYYY-MM-DD HH24:MI:SS"), fetch.content
];
//执行sql,数据库中fetch表里的url属性是unique的,不会把重复的url内容写入数据库
mysql.query(fetchAddSql, fetchAddSql_Params, function(qerr, vals, fields) {
if (qerr) {
console.log(qerr);
}
}); //mysql写入
});
}
(思路过程大致一致,因此不再一一赘述)
结果
前端设计
<!DOCTYPE html>
<html>
<header>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</header>
<head>
<style type="text/css">
body
{background-image:
url("images/14.jpg");
}
p{
color:red;
}
</style>
</head>
<body>
<Embed src="Floating.mp3",width="0"height="0"AUTOSTART="TRUE│false" LOOP="TRUE"></Embed>
<p>
<form>
<br> 标题:<input type="text" name="title_text">
<input class="form-submit" type="button" value="查询">
</form>
<div class="cardLayout" style="margin: 10px 0px">
<table width="100%" id="record2"></table>
</div>
</p>
<script>
$(document).ready(function() {
$("input:button").click(function() {
$.get('/process_get?title=' + $("input:text").val(), function(data) {
$("#record2").empty();
$("#record2").append('<tr class="cardLayout"><td>url</td><td>source_name</td>' +
'<td>title</td><td>author</td><td>publish_date</td></tr>');
for (let list of data) {
let table = '<tr class="cardLayout"><td>';
Object.values(list).forEach(element => {
table += (element + '</td><td>');
});
$("#record2").append(table + '</td></tr>');
}
});
});
});
</script>
</body>
</html>
啊
啊啊啊啊啊啊,前两周的时候就一直在研究html的语法,后来得知爬虫主要是用js写,然后html和css只起了锦上添花的功能,就放下了一段时间,这次也是临时再将知识回顾,做了个简单的背景和背景音乐;
那个颜色不知道怎么的就一直改不来,害
咦,放大后为什么分块了?!往下滑为什么也分块了?!还不会做动图wuwuwu
后来将细节进行了改动
<head>
<title>
东方财富网爬虫
</title>
</head>
<body background="images/17.jpeg"
style="background-repeat: no-repeat;
background-size:100% 100%;
background-attachment:fixed;">
<h1>爬虫……</h1>
<Embed src="Floating.mp3",width="0"height="0"AUTOSTART="TRUE│false" LOOP="TRUE"></Embed>
效果呈现
爬虫代码运行中常出现的错误
(PS:上述错误出现在output之后,不影响爬虫结果,但以我浅薄的知识水平无法解决,还请各路dalao解答
后来问老师过后,可能是格式的问题,把date注释掉就可以了
这也是为什么我的前端呈现中date那一栏为null啊,)
附各种文件
写在最后
只写过一学期C语言的前端开发小白,从零开始,磕磕绊绊,主要根据老师的教学逐步推进,以此记录开发全程!
至于选择了两个财经类网站,纯属巧合,最近恰好对理财基金比较关注~~(捂脸)~~
此外,在开发过程中,发现一开始那种抱着掌握所有的基础知识再开始着笔的方式,完全不适合我,故再后期以看代码为主,重点分析他人代码,然后再进行对应地搜索,以此获得了许多的基础知识。
(部分代码来源于教学,刚开始较盲目的时候观看多位老师的视频,后期也主要以修改老师代码为主)
另外,由于刚开始的思路跟老师最终的要求不同,整篇文章几乎重新更改,很多逻辑、排版也没有仔细推敲,还拖了这么久(呜呜呜)