c#.net——c#.net异步实现网页信息爬取


之前研究各种语言异步的时候就想做一个C#版本的异步,但是毕竟好久不做了(也就是在大学期间用asp.net做了几个管理系统)

一开始写代码时完全蒙蔽了,语法啥的都忘差不多了~~研究了好几天,也参考了网上许多资料,终于写出了几行low逼代码



实现内容:异步并发爬取网页信息


首先异步的语法和其他语言都大同小异,async、await,定义异步方法的话要加async修饰符,如果你想在await调用,那么返回值必须为 Task



若返回值为Task,但是我们并没有await,也就是阻塞时返回继续执行,VS编译器也会给予提示,但可以正常运行





接下来说一下爬取程序的实现,也是也很简单,就是HTML匹配抓取关键字

先写一个方法 实现文本截取

    public static string get_key_by_content(string content, string start, string end)
    {
        if (content.Contains(start) && content.Contains(end))
        {
            int start_point = content.IndexOf(start, 0, System.StringComparison.Ordinal) + start.Length;
            int end_point = content.IndexOf(end, start_point, System.StringComparison.Ordinal);
            return content.Substring(start_point, end_point - start_point);
        }
        else
        {
            return "";
        }
    }


以CSDN博客为例,截取标题、阅读量等信息



我们发现标题有一个超链接,于是我们把帖子的子url摘出来

                string link_view = Common.get_key_by_content(content, "<span class=\"link_view\" title=\"阅读次数\">", "</span>");
                string link_title = Common.get_key_by_content(content, "<span class=\"link_title\"><a href=\"/"+childurl+"\">", "</a>");


整个爬取函数:

 static async Task Spider(string RootUrl, int child, string childurl)
    {

        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(RootUrl);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));

            try
            {
                HttpResponseMessage response = await client.GetAsync(childurl);
                response.EnsureSuccessStatusCode();   
                string content = await response.Content.ReadAsStringAsync();
                string link_view = Common.get_key_by_content(content, "<span class=\"link_view\" title=\"阅读次数\">", "</span>");
                string link_title = Common.get_key_by_content(content, "<span class=\"link_title\"><a href=\"/"+childurl+"\">", "</a>");
                Console.WriteLine("第" + (child + 1).ToString() + "个帖子 " + link_title+"   "+link_view);
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine(e.Message);
            }
        }

    }


然后我们定义执行异步任务函数

static async void StartTask(string url)
    {
        for (int p = 0; p < Common.get_article_length(); p++)
        {
            //await WhileRun(url, p, Common.get_article_by_id(p));
            WhileRun(url, p, Common.get_article_by_id(p));
        }

    }

    static async Task WhileRun(string RootUrl, int p, string childurl)
    {
        while (true)
        {
            await Spider(RootUrl, p, childurl);
            Thread.Sleep(1000);
        }
    }


接下来只要定义几个帖子就可以了,由于C#没有全局的概念,所以我们要封装成一个类,同时给出获取帖子地址、帖子总数长度等方法。


完整代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;



public class Common
{
    static string[] articles = {
      "sm9sun/article/details/75395020",
      "sm9sun/article/details/75446875",
      "sm9sun/article/details/75449050",
      "sm9sun/article/details/75735001",
      "sm9sun/article/details/75309443",
      "sm9sun/article/details/76358660"
    };


    public static string get_article_by_id(int id)
    {
        if(id < articles.Length&&id>=0)
        {
            return articles[id];
        }
        else
        {
            return "error";
        }
    }

    public static int get_article_length()
    {
        return articles.Length;
    }

    public static string get_key_by_content(string content, string start, string end)
    {
        if (content.Contains(start) && content.Contains(end))
        {
            int start_point = content.IndexOf(start, 0, System.StringComparison.Ordinal) + start.Length;
            int end_point = content.IndexOf(end, start_point, System.StringComparison.Ordinal);
            return content.Substring(start_point, end_point - start_point);
        }
        else
        {
            return "";
        }
    }



}

class Program
{

    static void Main()
    {
        string RootUrl = "http://blog.csdn.net";
        StartTask(RootUrl);
        Console.WriteLine("gogogo!");
        Console.ReadLine();

    }

    static async void StartTask(string url)
    {
        for (int p = 0; p < Common.get_article_length(); p++)
        {
            //await WhileRun(url, p, Common.get_article_by_id(p));
            WhileRun(url, p, Common.get_article_by_id(p));
        }

    }

    static async Task WhileRun(string RootUrl, int p, string childurl)
    {
        while (true)
        {
            await Spider(RootUrl, p, childurl);
            Thread.Sleep(1000);
        }
    }

    static async Task Spider(string RootUrl, int child, string childurl)
    {

        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(RootUrl);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));

            try
            {
                HttpResponseMessage response = await client.GetAsync(childurl);
                response.EnsureSuccessStatusCode();   
                string content = await response.Content.ReadAsStringAsync();
                string link_view = Common.get_key_by_content(content, "<span class=\"link_view\" title=\"阅读次数\">", "</span>");
                string link_title = Common.get_key_by_content(content, "<span class=\"link_title\"><a href=\"/"+childurl+"\">", "</a>");
                Console.WriteLine("第" + (child + 1).ToString() + "个帖子 " + link_title+"   "+link_view);
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine(e.Message);
            }
        }

    }
}


运行截图:






顺带一提,我不是故意刷阅读量的~!~!

不是~!~!

真的不是~!~!





描述:由C#编写的多线程异步抓取网页的网络爬虫控制台程序 功能:目前只能提取网络链接,所用的两个记录文件并不需要很大。网页文本、图片、视频和html代码暂时不能抓取,请见谅。 但需要注意,网页的数目是非常庞大的,如下代码理论上大概可以把整个互联网网页链接都抓下来。 但事实上,由于处理器功能和网络条件(主要是网速)限制,一般的家用电脑最多能胜任12个线程左右的抓取任务,抓取速度有限。可以抓取,但需要时间和耐心。 当然,这个程序把所有链接抓下来是可能的,因为链接占系统空间并不多,而且有记录文件的帮助,已抓取网页的数量可以堆积下去, 甚至可以把所有的互联网网络链接都存取下来,当然,最好是分批次。建议设置maxNum为500-1000左右,慢慢累积下去。 另外因为是控制台程序,有时候显示字符过多会系统会暂停显示,这时候只要点击控制台按下回车键就可以了。程序假死的时候,可以按回车键(Enter)试试。 /// 使用本程序,请确保已创建相应的记录文件,出于简化代码的考虑,本程序做的并不健壮,请见谅。 /// 默认的文件创建在E盘根目录“已抓取网址.txt”和“待抓取网址.txt”这两个文本文件中,使用者需要自行创建这两个文件,注意后缀名不要搞错。 这两个文件里面的链接基本都是有效链接,可以单独处理使用。 本爬虫程序的速度如下: 10线程最快大概500个链接每分钟 6-8线程最快大概400-500个链接每分钟 2-4线程最快大概200-400个链接每分钟 单线程最快大概70-100个链接每分钟 之所以用多线程异步抓取完全是出于效率考虑,本程序多线程同步并不能带来速度的提升,只要抓取的网页不要太多重复和冗余就可以,异步并不意味着错误。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值