7月 25

当程序出现错误的时候将会调用

    public class ExceptionFilter : IExceptionFilter
    { 
        public void OnException(ExceptionContext context)
        { 
            var url = context.HttpContext.Request.Host + context.HttpContext.Request.Path;

            LogHelper.Error(url);
            LogHelper.Error(context.Exception);
        }
    }

全局注入方法

            services.AddMvc(
                config =>
                { 
                    config.Filters.Add(new ExceptionFilter());
                });

written by ocean

7月 23

测试了好几个以前的类都跑不起来,于是灵机一动,在网页中播放声音

                ProcessStartInfo startInfo = new ProcessStartInfo(@"C:\Program Files\Internet Explorer\iexplore.exe");
                startInfo.Arguments = "http://music.163.com/#/outchain/2/28406526/";
                Process process1 = new Process();
                process1.StartInfo = startInfo;
                process1.Start();

虽然不雅,但是在我的场景下是适用的。

written by ocean

7月 11

 一个标签中,同时有 col-xs , col-sm , col-md , col-lg

.col-xs- 超小屏幕 手机 (<768px)

.col-sm- 小屏幕 平板 (≥768px)

.col-md- 中等屏幕 桌面显示器 (≥992px)

.col-lg- 大屏幕 大桌面显示器 (≥1200px)

<div class="col-xs-12 col-sm-9 col-md-6 col-lg-3">                        
</div>

当屏幕尺寸

小于 768px 的时候,用 col-xs-12 类对应的样式;

在 768px 到 992px 之间的时候,用 col-sm-9 类对应的样式;

在 992px 到 1200px 之间的时候,用 col-md-6 类对应的样式;

大于 1200px 的时候,用 col-lg-3 类对应的样式;

written by ocean

7月 08

首先安装JAVA,安装完之后查看版本正常说明OK

java -version

下载android SDK并且添加环境变量

key : ANDROID_HOME
value : D:\Green\android\android-sdk

打开Android SDK Manager。选中以下项目:

Android SDK Build-tools version 23.0.1
Android 6.0 (API 23)
Android Support Repository
Local Maven repository for Support Libraries

下载完之后,将sdk配置到windows环境变量Path中

D:\Green\android\android-sdk\tools;
D:\Green\android\android-sdk\platform-tools

安装Node.js

https://nodejs.org/en/

安装Gith

https://git-for-windows.github.io/

如果是绿色版本要加入path环境变量 

 

运行起来,键入命令

react-native run-android

出现错误

* What went wrong:
A problem occurred configuring project ':app'.
> SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.

在react native 项目的android目录下新建文件local.properties添加字段

sdk.dir = D:\\Green\\android\\android-sdk

 出现错误

 What went wrong:
Execution failed for task ':app:installDebug'.
> com.android.builder.testing.api.DeviceException: No connected devices!

这是因为avd没有运行,运行起来即可

written by ocean

7月 05

Console程序中 中文乱码 

引用包

System.Text.Encoding.CodePages

在程序开头调用

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

 

项目发布到ubuntu上

命令行定位到web项目目录

dotnet  publish -r ubuntu.16.04-x64

written by ocean

7月 03

PIP是python下的一个包管理工具

一般直接命令即可

pip install XXX

但是因为国内网络的一些原因,经常会出现超时

可以用国内镜像代替

pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

这个是清华大学的镜像,测试下来发现非常快

written by ocean

7月 02

首先需要安装PyMySQL

PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。

pip install PyMySQL

 

添加数据

import pymysql
#打开数据库连接
db = pymysql.connect("localhost","root","root","db_zuowen",charset='utf8')
#使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor() 
sql="insert into tb_zuowen values ('16211','2222','2017-08-08 00:00:00',1,0)"
#执行SQL语句
cursor.execute(sql)
db.commit()
db.close()

查询数据

import pymysql
#打开数据库连接
db = pymysql.connect("localhost","root","root","db_zuowen",charset='utf8')
#使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor() 
sql="select url,addDate from tb_zuowen limit 10"
#执行SQL语句
cursor.execute(sql)
#获取所有记录列表
results = cursor.fetchall()
for row in results:
    url=row[0]
    addDate=row[1]
    print('url=%s AND addDate=%s'%(url,addDate))
db.close()

更新数据

import pymysql
#打开数据库连接
db = pymysql.connect("localhost","root","root","db_zuowen",charset='utf8')
#使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor() 
sql="update tb_zuowen set Type='72' WHERE url='16211'"
#执行SQL语句
cursor.execute(sql)
# 提交到数据库执行
db.commit() 
db.close()

删除数据

import pymysql
#打开数据库连接
db = pymysql.connect("localhost","root","root","db_zuowen",charset='utf8')
#使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor() 
sql="DELETE FROM tb_zuowen WHERE Type>'%d'" %(20)
#执行SQL语句
cursor.execute(sql)
# 提交到数据库执行
db.commit()
#关闭连接
db.close()

written by ocean

7月 01

using HtmlAgilityPack;

using System;

using System.Net.Http;

namespace ConsoleApp1

{

    class Program

    {

        private static HttpClient client = new HttpClient();

        static void Main(string[] args)

        {

            int page = 0;

            bool hasNextPage = true;

            while (hasNextPage)

            {

                page++;

                string u = "http://del.chinaz.com/?kw=&p=0&el=6&ds%5B%5D=1&ds%5B%5D=2&py=1&pl=0&sort=1&suffix%5B%5D=com&suffix%5B%5D=net&dt=0&date=2017-07-15&ba=1&pro=%e5%85%a8&xz=%e5%85%a8%e9%83%a8&cn_txt=&pagesize=30&page="+page;

                var htm = client.GetStringAsync(u).Result;

                HtmlDocument doc = new HtmlDocument();

                doc.LoadHtml(htm);

                var nodes = doc.DocumentNode.SelectNodes("/html/body/div[2]/div[2]/ul/li");

                if (nodes != null && nodes.Count == 31)

                    hasNextPage = true;

                else

                {

                    hasNextPage = false;

                }

                if (nodes == null)

                    continue;

                for (int index = 0; index < nodes.Count; index++)

                {

                    if (index == 0) continue;

                    var value = nodes[index].SelectSingleNode("div[1]/a").InnerHtml;

                    

                        Console.Write(value);

                    if (IsCanRegedit(value))

                    {

                        Console.Write(" Can Regist ");

                        if (CheckQQIsOK(value))

                        { 

                            Console.Write(" QQ OK ");

                            if (IsBeiAn(value))

                            {

                                Console.Write(" BeiAn OK ");

                                LogHelper.Info(value);

                            }

                        }

                    }

                    

                    Console.WriteLine();

                  

                     

                }

            }

            

            //

            Console.WriteLine("Hello World!");

        }

        

            

private static bool IsBeiAn(string url)

        {

            var c = "http://www.soicp.com/index.html?type=1&value=" + url;

            var html = client.GetStringAsync(c).Result;

            return html.Contains("没有找到相关记录") == false;

        }

private static bool IsCanRegedit(string url)

{

    var c = "http://www.qiuyumi.com/whois/?domain=" + url;

    var html = client.GetStringAsync(c).Result;

            return html.Contains("已被注册")==false;

}

private static bool CheckQQIsOK(string url)

        {

            if (!url.StartsWith("http"))

            {

                url = "http://" + url;

            }

            string c = "http://cgi.urlsec.qq.com/index.php?m=check&a=check&callback=url_query&url="+url;

            var json = client.GetStringAsync(c).Result;

            if (json.Contains("\"whitetype\":2"))

            {

                return false;

            }

            return true;

        }

    }

}

written by ocean

6月 28

之前有记录一篇提取网页正文的算法

提取网页正文的通用算法

 

发现在一些文章上提取效果不是很理想。后来发现了 Raedability网站(www.readability.com)

它最引以为傲的就是其强大的解析引擎, 号称世界上最强大的文本解析神器. Safari中的"阅读器"功能就是用它来实现的! 他们还提供了API可以调用解析器的功能

 

网上找了一个包装代理类,发现已经失效了。自己写了一个,依然用的.net core

    public static class ReadabilityProxy
    { 
        private static HttpClient httpClient = new HttpClient();
        public static Article Parse(string url, string token) //token就是各位的appkey
        {
            var encUrl = WebUtility.UrlEncode(url);
            Uri u = new Uri(string.Format("https://mercury.postlight.com/parser?url={0}", encUrl, token));
            httpClient.DefaultRequestHeaders.Add("x-api-key", token);
            var json = httpClient.GetStringAsync(u).Result;
            var article = Newtonsoft.Json.JsonConvert.DeserializeObject<Article>(json);
            article.Decode();
            return article;
        } 
    }
    
    public class Article
    {
        public string Domain;
        public string Next_Page_Id;
        public string Url;
        public string Content;
        public string Short_Url;
        public string Excerpt;
        public string Direction;
        public int Word_Count;
        public int Total_Pages;
        public string Date_Published;
        public string Dek;
        public string Lead_Image_Url;
        public string Title;
        public int Rendered_Pages;

        public virtual void Decode()
        {
            this.Excerpt = WebUtility.HtmlDecode(this.Excerpt);
            this.Content = WebUtility.HtmlDecode(this.Content);
        }
    }

调用方式

    static void Main(string[] args)
    {
        var article = ReadabilityProxy.Parse("http://blog.wx6.org/", 
            "5yf880mid1fMlpVUEDFaw3mquGCuzzzxAJhrqn1x");
        article.Decode();
        Console.WriteLine(article.Title);
        Console.WriteLine(article.Excerpt);
        Console.WriteLine(article.Content);
        Console.ReadLine();
    }

 

不过实际效果发现也不是很完美 

written by ocean

6月 22

做采集会用到提取网页正文的功能。

找到一个 《基于行块分布函数的通用网页正文抽取算法》

已经有一个实现方式了,项目名称Html2Article 原作者不支持.net core

因为我要在 .net core 中使用,所以github上找到源代码,稍作修改

调用方式很简单

var article=Html2Article.GetArticle(html); 
Console.WriteLine(article.ContentWithTags);

 

纪录下来改过的源代码

   /// <summary>
    /// 文章正文数据模型
    /// </summary>
    public class Article
    {
        /// <summary>
        /// 文章标题
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// 正文文本
        /// </summary>
        public string Content { get; set; }
        /// <summary>
        /// 带标签正文
        /// </summary>
        public string ContentWithTags { get; set; }
        /// <summary>
        /// 文章发布时间
        /// </summary>
        public DateTime PublishDate { get; set; }
    }
     
    public class Html2Article
    {
        #region 参数设置

        // 正则表达式过滤:正则表达式,要替换成的文本
        private static readonly string[][] Filters =
        {
            new[] { @"(?is)<script.*?>.*?</script>", "" },
            new[] { @"(?is)<style.*?>.*?</style>", "" },
            new[] { @"(?is)<!--.*?-->", "" },    // 过滤Html代码中的注释
            // 针对链接密集型的网站的处理,主要是门户类的网站,降低链接干扰
            new[] { @"(?is)</a>", "</a>\n"}
        };

        private static bool _appendMode = false;
        /// <summary>
        /// 是否使用追加模式,默认为false
        /// 使用追加模式后,会将符合过滤条件的所有文本提取出来
        /// </summary>
        public static bool AppendMode
        {
            get { return _appendMode; }
            set { _appendMode = value; }
        }

        private static int _depth = 6;
        /// <summary>
        /// 按行分析的深度,默认为6
        /// </summary>
        public static int Depth
        {
            get { return _depth; }
            set { _depth = value; }
        }

        private static int _limitCount = 180;
        /// <summary>
        /// 字符限定数,当分析的文本数量达到限定数则认为进入正文内容
        /// 默认180个字符数
        /// </summary>
        public static int LimitCount
        {
            get { return _limitCount; }
            set { _limitCount = value; }
        }

        // 确定文章正文头部时,向上查找,连续的空行到达_headEmptyLines,则停止查找
        private static int _headEmptyLines = 2;
        // 用于确定文章结束的字符数
        private static int _endLimitCharCount = 20;

        #endregion

        /// <summary>
        /// 从给定的Html原始文本中获取正文信息
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static Article GetArticle(string html)
        {
            // 如果换行符的数量小于10,则认为html为压缩后的html
            // 由于处理算法是按照行进行处理,需要为html标签添加换行符,便于处理
            int tagCount = 0;
            for (int index = 0; index < html.Length; index++)
            {
                if (html[index] == '\n')
                {
                    tagCount++;
                }
            }
            if (tagCount < 10)
            {
                html = html.Replace(">", ">\n");
            }

            // 获取html,body标签内容
            string body = "";
            string bodyFilter = @"(?is)<body.*?</body>";
            Match m = Regex.Match(html, bodyFilter);
            if (m.Success)
            {
                body = m.ToString();
            }
            // 过滤样式,脚本等不相干标签
            foreach (var filter in Filters)
            {
                body = Regex.Replace(body, filter[0], filter[1]);
            }
            // 标签规整化处理,将标签属性格式化处理到同一行
            // 处理形如以下的标签:
            //  <a 
            //   href='http://www.baidu.com'
            //   class='test'
            // 处理后为
            //  <a href='http://www.baidu.com' class='test'>
            body = Regex.Replace(body, @"(<[^<>]+)\s*\n\s*", FormatTag);

            string content;
            string contentWithTags;
            GetContent(body, out content, out contentWithTags);

            Article article = new Article
            {
                Title = GetTitle(html),
                PublishDate = GetPublishDate(body),
                Content = content,
                ContentWithTags = contentWithTags
            };

            return article;
        }

        /// <summary>
        /// 格式化标签,剔除匹配标签中的回车符
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        private static string FormatTag(Match match)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var ch in match.Value)
            {
                if (ch == '\r' || ch == '\n')
                {
                    continue;
                }
                sb.Append(ch);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 获取时间
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private static string GetTitle(string html)
        {
            string titleFilter = @"<title>[\s\S]*?</title>";
            string h1Filter = @"<h1.*?>.*?</h1>";
            string clearFilter = @"<.*?>";

            string title = "";
            Match match = Regex.Match(html, titleFilter, RegexOptions.IgnoreCase);
            if (match.Success)
            {
                title = Regex.Replace(match.Groups[0].Value, clearFilter, "");
            }

            // 正文的标题一般在h1中,比title中的标题更干净
            match = Regex.Match(html, h1Filter, RegexOptions.IgnoreCase);
            if (match.Success)
            {
                string h1 = Regex.Replace(match.Groups[0].Value, clearFilter, "");
                if (!String.IsNullOrEmpty(h1) && title.StartsWith(h1))
                {
                    title = h1;
                }
            }
            return title;
        }

        /// <summary>
        /// 获取文章发布日期
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private static DateTime GetPublishDate(string html)
        {
            // 过滤html标签,防止标签对日期提取产生影响
            string text = Regex.Replace(html, "(?is)<.*?>", "");
            Match match = Regex.Match(
                text,
                @"((\d{4}|\d{2})(\-|\/)\d{1,2}\3\d{1,2})(\s?\d{2}:\d{2})?|(\d{4}年\d{1,2}月\d{1,2}日)(\s?\d{2}:\d{2})?",
                RegexOptions.IgnoreCase);

            DateTime result = new DateTime(1900, 1, 1);
            if (match.Success)
            {
                try
                {
                    string dateStr = "";
                    for (int i = 0; i < match.Groups.Count; i++)
                    {
                        dateStr = match.Groups[i].Value;
                        if (!String.IsNullOrEmpty(dateStr))
                        {
                            break;
                        }
                    }
                    // 对中文日期的处理
                    if (dateStr.Contains("年"))
                    {
                        StringBuilder sb = new StringBuilder();
                        foreach (var ch in dateStr)
                        {
                            if (ch == '年' || ch == '月')
                            {
                                sb.Append("/");
                                continue;
                            }
                            if (ch == '日')
                            {
                                sb.Append(' ');
                                continue;
                            }
                            sb.Append(ch);
                        }
                        dateStr = sb.ToString();
                    }
                    result = Convert.ToDateTime(dateStr);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                if (result.Year < 1900)
                {
                    result = new DateTime(1900, 1, 1);
                }
            }
            return result;
        }

        /// <summary>
        /// 从body标签文本中分析正文内容
        /// </summary>
        /// <param name="bodyText">只过滤了script和style标签的body文本内容</param>
        /// <param name="content">返回文本正文,不包含标签</param>
        /// <param name="contentWithTags">返回文本正文包含标签</param>
        private static void GetContent(string bodyText, out string content, out string contentWithTags)
        {
            string[] orgLines = null;   // 保存原始内容,按行存储
            string[] lines = null;      // 保存干净的文本内容,不包含标签

            orgLines = bodyText.Split('\n');
            lines = new string[orgLines.Length];
            // 去除每行的空白字符,剔除标签
            for (int i = 0; i < orgLines.Length; i++)
            {
                string lineInfo = orgLines[i];
                // 处理回车,使用[crlf]做为回车标记符,最后统一处理
                lineInfo = Regex.Replace(lineInfo, "(?is)</p>|<br.*?/>", "[crlf]");
                lines[i] = Regex.Replace(lineInfo, "(?is)<.*?>", "").Trim();
            }

            StringBuilder sb = new StringBuilder();
            StringBuilder orgSb = new StringBuilder();

            int preTextLen = 0;         // 记录上一次统计的字符数量
            int startPos = -1;          // 记录文章正文的起始位置
            for (int i = 0; i < lines.Length - _depth; i++)
            {
                int len = 0;
                for (int j = 0; j < _depth; j++)
                {
                    len += lines[i + j].Length;
                }

                if (startPos == -1)     // 还没有找到文章起始位置,需要判断起始位置
                {
                    if (preTextLen > _limitCount && len > 0)    // 如果上次查找的文本数量超过了限定字数,且当前行数字符数不为0,则认为是开始位置
                    {
                        // 查找文章起始位置, 如果向上查找,发现2行连续的空行则认为是头部
                        int emptyCount = 0;
                        for (int j = i - 1; j > 0; j--)
                        {
                            if (String.IsNullOrEmpty(lines[j]))
                            {
                                emptyCount++;
                            }
                            else
                            {
                                emptyCount = 0;
                            }
                            if (emptyCount == _headEmptyLines)
                            {
                                startPos = j + _headEmptyLines;
                                break;
                            }
                        }
                        // 如果没有定位到文章头,则以当前查找位置作为文章头
                        if (startPos == -1)
                        {
                            startPos = i;
                        }
                        // 填充发现的文章起始部分
                        for (int j = startPos; j <= i; j++)
                        {
                            sb.Append(lines[j]);
                            orgSb.Append(orgLines[j]);
                        }
                    }
                }
                else
                {
                    //if (len == 0 && preTextLen == 0)    // 当前长度为0,且上一个长度也为0,则认为已经结束
                    if (len <= _endLimitCharCount && preTextLen < _endLimitCharCount)    // 当前长度为0,且上一个长度也为0,则认为已经结束
                    {
                        if (!_appendMode)
                        {
                            break;
                        }
                        startPos = -1;
                    }
                    sb.Append(lines[i]);
                    orgSb.Append(orgLines[i]);
                }
                preTextLen = len;
            }

            string result = sb.ToString();
            // 处理回车符,更好的将文本格式化输出
            content = result.Replace("[crlf]", Environment.NewLine);
            content =  WebUtility.HtmlDecode(content);
            // 输出带标签文本
            contentWithTags = orgSb.ToString();
        }


        /// <summary>
        /// 基于baseUrl,补全html代码中的链接
        /// </summary>
        /// <param name="baseUrl"></param>
        /// <param name="html"></param>
        public static string FixUrl(string baseUrl, string html)
        {
            html = Regex.Replace(html, "(?is)(href|src)=(\"|\')([^(\"|\')]+)(\"|\')", (match) =>
            {
                string org = match.Value;
                string link = match.Groups[3].Value;
                if (link.StartsWith("http"))
                {
                    return org;
                }

                try
                {
                    Uri uri = new Uri(baseUrl);
                    Uri thisUri = new Uri(uri, link);
                    string fullUrl = String.Format("{0}=\"{1}\"", match.Groups[1].Value, thisUri.AbsoluteUri);
                    return fullUrl;
                }
                catch (Exception)
                {
                    return org;
                }
            });
            return html;
        }

    }

 

written by ocean