百度搜索指定网站内容(vs2012如何查询某个网址的收录次数5,280,000这段)
优采云 发布时间: 2022-02-16 14:00百度搜索指定网站内容(vs2012如何查询某个网址的收录次数5,280,000这段)
一、前言
偶然在vs2012的默认项目文件夹中发现了一个我之前做的关于SEO的类库。主要用于查询某网站收录的数量和网站的排名数量。后来经过重构,今天拿出来写了一篇文章文章,告诉我我是怎么想的,怎么完成的。
二、问题描述
首先要考虑的是可以支持哪些搜索引擎查询,首先是百度,然后是必应、搜狗、搜搜、360。本来想支持谷歌的,但是没想到,不好访问全部,所以暂时不包括在内。我们真正需要做的是,根据一个URL,检索这个URL在各个搜索引擎中的收录次数,以及不同关键词下的URL排名。只有 URL 和几个 关键词 进出。@关键词,输出为该URL在不同搜索引擎下的收录次数和每个关键词下的排名次数。
但是这里有一个问题,就是排名的数量。如果检索到的 URL 在前 100 位,那就没问题了。如果排名很低,那么问题就来了,这会让用户等待很长时间才能看到结果,但用户可能只想知道前100名的具体排名,超过100名的只需要展示出来,这些都需要前期考虑好,方便后续的流程。
三、解决方案
相信很多人都能想到,就是用WebClient下载需要的页面,然后用正则得到我们感兴趣的部分,再用程序进行处理。关键难点在这个正则的写法上,首先我们从一个简单的说起。
四、收录次数
首先是网站的收录的编号,我们可以在百度中输入site:,然后可以看到如下页面:
而我们需要收录的次数是5,280,000,那么我们来看一下页面元素:
然后我们再看其他搜索引擎,发现都差不多,所以这个时候我们的思路就应该画出来了,最后就是如何组织URL。在这部分,我们看看地址栏?wd=site%3A%2F 就知道怎么写了。
这时候我们可能会迫不及待地一一实现,这样以后就不能集中调用了,也会影响以后的添加,所以需要指定一个抽象类来实现收录@ > number 函数,这样就可以在不知道具体实现的情况下统一使用,而且以后可以方便的添加新的搜索引擎,这种方式属于策略模式(Stategry)。让我们慢慢分析这个抽象类的具体内容。
首先,实现这个抽象类的每个具体类都应该对应某个搜索引擎,所以它需要有一个基本的URL,并留一个占位符。比如根据上面的百度,我们可以得到这样一个字符串
%3A{0}
其中,{0} 是真正需要检索的 URL 的占位符。获取下载页面的路径是所有具体类都需要的,所以我们直接把实现放到抽象类中,比如下面的代码:
复制代码代码如下:
///
/// 服务供应商
///
受保护的字符串 SearchProvider { get; 放; }
///
/// 要检索的 URL
///
受保护的字符串 SiteUrl { 获取;放; }
///
/// 搜索服务提供者 URL
///
受保护的字符串 BaseUrl { 获取;放; }
///
/// 后页地址
///
///
要查询的网址
/// 连接的 URL
受保护的字符串 GetDownUrl(字符串站点)
{
return string.Format(BaseUrl, HttpUtility.UrlEncode(site));
}
其中,SiteUrl 和 SearchProvider 用于保存检索 URL 和搜索引擎名称。
上面我们说过会使用WebClient来下载页面,所以初始化WebClient的工作也是在抽象类中完成的,尽可能减少重复代码,并且为了防止阻塞当前线程,我们使用了Async方法。
具体代码如下:
复制代码代码如下:
///
/// 此搜索引擎中 收录 查询的数量
///
///
网站网址
公共无效 SearchIncludeCount(字符串站点网址)
{
网站网址 = 网站网址;
WebClient 客户端 = 新 WebClient();
client.Encoding = Encoding.UTF8;
client.DownloadStringCompleted += DownloadStringCompleted;
client.DownloadStringAsync(new Uri(GetDownUrl(siteurl)));
}
///
/// 检索次数的具体实现 收录
/// 子类必须实现这个方法
///
///
///
受保护的抽象无效DownloadStringCompleted(对象发送者,DownloadStringCompletedEventArgs e);
当WebClient完成下载后,会回调DownloadStringCompleted方法,这个方法是抽象方法,也就是说具体的类必须实现这个方法。
虽然我们的内部实现是异步的,但是其他开发者调用这个方法仍然是同步的,所以我们需要使用委托,所以我们还需要创建一个新的委托类型:
复制代码代码如下:
///
/// 网站的收录查询完成时回调
///
公共操作 OnComplatedOneSite { 获取;放; }
SiteIncludeCountResult 的结构如下:
复制代码代码如下:
///
/// 网站收录 中代表的参数
///
公共类 SiteIncludeCountResult
{
///
/// 收录次数
///
公共长包括计数 { 得到;放; }
///
/// 搜索引擎类型
///
公共字符串搜索类型 { 获取;放; }
///
/// 网站网址
///
公共字符串 SiteUrl { 获取;放; }
}
最后还有一个方法可以在 DownloadStringCompleted 完成时回调 OnComplatedOneSite 委托:
///
/// 处理后调用该方法返回结果
///
///
收录 URL 的计数结果
protected void SetCompleted(SiteIncludeCountResult 结果)
{
如果(OnComplatedOneSite != null)
OnComplatedOneSite(结果);
}
这样,我们需要的抽象类就完成了。现在我们可以开始实现第一个。从上面的截图中,我们可以发现匹配这个字符串的正则表达式非常简单:
复制代码代码如下:
百度为您找到关于 ([\w,]+?) 的相关结果
最后,你可以通过从获得的字符串中删除逗号来强制转换,结果就会出来。具体实现如下:
复制代码代码如下:
///
/// 百度网站收录次查询
///
公共类 BaiDuSiteIncludeCount : SiteIncludeCountBase
{
public BaiDuSiteIncludeCount()
{
BaseUrl = "{0}";
SearchProvider = "百度";
}
protected override void DownloadStringCompleted(对象发送者,DownloadStringCompletedEventArgs e)
{
var 结果 = 新 SiteIncludeCountResult();
结果.SiteUrl = SiteUrl;
结果.SearchType = SearchProvider;
结果.IncludeCount = 0;
Regex reg = new Regex(@"百度为你找到了大约([\w,]+?)个相关结果", RegexOptions.IgnoreCase | RegexOptions.Singleline);
var 匹配 = reg.Matches(e.Result);
if (matchs.Count > 0)
{
字符串计数 = 匹配[0].Groups[1].Value.Replace(",", "");
result.IncludeCount = long.Parse(count);
}
设置完成(结果);
}
}
以此类推,其他的都是按照这个来的,有兴趣的可以下载我的源码查看。
五、关键词排名
按照之前的思路,我们还是需要先指定一个抽象类,但是它的结构和上面的抽象类很相似,所以作者在这里直接给出具体代码:
复制代码代码如下:
///
/// 实现 关键词 查询必须继承这个类
///
公共抽象类 KeyWordsSeoBase
{
受保护的字符串 BaseUrl { 获取;放; }
受保护的字符串 SearchProvider { get; 放; }
protected String GetDownUrl(字符串关键字,字符串站点,长电流)
{
return String.Format(BaseUrl, HttpUtility.UrlEncode(keyword), current);
}
protected void SetCompleted(KeyWordsSeoResult 结果)
{
如果(OnComplatedOneKeyWord != null)
{
OnComplatedOneKeyWord(结果);
}
}
///
/// 完成 关键词 查询后回调委托
///
公共操作 OnComplatedOneKeyWord { 获取;放; }
///
/// 查询指定关键词和网站在搜索引擎中的排名
/// 子类需要重写这个方法
///
///
关键词
///
网站网址
public abstract void SearchRanking(IEnumerable keywords, string site, long count);
}
最大的不同是具体实现都集中在SearchRanking。从keywords参数可以看出,我们将支持多个关键词查询。最后一个区别是下载路径的组织。因为它涉及翻页,所以有一个额*敏*感*词*。
KeyWordsSeoResult 的结构如下:
复制代码代码如下:
///
/// 关键词 排名查询的委托参数
///
公共类 KeyWordsSeoResult
{
///
/// 搜索引擎类型
///
公共字符串搜索类型 { 获取;放; }
///
/// 关键词
///
公共字符串关键字 { 获取;放; }
///
/// 排行
///
public long Ranking { 得到;放; }
}
废话不多说,我们来看百度的搜索结果页面:
以上是笔者在百度搜索程序员的第九个html结构。您可能认为获取 div 的 id 和 URL 非常简单。但是很多搜索引擎的路径并不是直接路径,而是会先链接到百度,然后再重定向。如果一定要匹配,我们还需要做一件事:访问这条路径获取真实路径,中间会增加等待时间,所以作者使用了上面的截图。中的后者内容,从而避免了请求。(不知道作者一开始是怎么想的,实现中并没有用到id值,而是内部自增,估计翻页后这个id的序号会有问题),最后展示我们神圣的正则表达式:
复制代码代码如下:
([^/&]*)
你认为这是一个重大的公告吗?错了,在某些结果中,百度会在这个网址上加ab标签,作者采用了全部杀掉的方法,使用正则规则全部删除(反正我不看页面,只要得到我要的,没关系),实现的时候不能直接实现多个关键词的识别,应该是实现一个关键词,然后循环调用。以下是作者单关键词的实现:
复制代码代码如下:
protected KeyWordsSeoResult SearchFunc(字符串键,字符串 siteurl,长总计)
{
var 结果 = 新的 KeyWordsSeoResult();
结果.KeyWord =键;
结果.排名=总+1;
var reg = new Regex(@"([^/&]*)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
var replace = new Regex("", RegexOptions.IgnoreCase | RegexOptions.Singleline);
var client = new WebClient();
长电流 = 0;
长位置 = 0;
为了 (; ; )
{
字符串 url = GetDownUrl(key, siteurl, current);
String downstr = client.DownloadString(url);
downstr = replace.Replace(downstr, "");
var 匹配 = reg.Matches(downstr);
foreach(匹配中的匹配)
{
正++;
字符串 suburl = match.Groups[1].Value;
尝试
{
if (suburl.ToLower() == siteurl.ToLower())
{
结果.Ranking = pos;
返回结果;
}
}
抓住
{
继续;
}
}
当前 += 10;
如果(当前>总计)
{
当前-= 10;
如果(当前 >= 总计)
{
休息;
}
当前=总计;
}
}
返回结果;
}
注意for循环的结束,用于处理分页,以便翻到下一页继续检索。其他通用部分和作者说的一样,下载页面->正则匹配->根据匹配结果判断。剩下的就是SearchRanking的实现,也就是循环关键词,不过这里我为每个搜索引擎新建一个线程来实现,当然这样不太好,读者可以用更好的方式来做它:
复制代码代码如下:
public override void SearchRanking(IEnumerable keywords, string site, long count)
{
新线程(()=>
{
foreach(关键字中的字符串键)
{
KeyWordsSeoResult 结果 = SearchFunc(key, site, count);
结果.SearchType = SearchProvider;
设置完成(结果);
}
})。开始();
}
六、统一管理
有了这些,我们就可以编写一个简洁的类来负责管理。作者在这里直接给出代码:
复制代码代码如下:
///
/// 查询网站的收录的个数和排名
///
公共类RankingAndIncludeSeo
{
///
/// 关键词列表
///
公共 IList KeyWordsSeoList { 获取;私人套装;}
///
/// 收录时间列表
///
公共 IList SiteIncludeCountList { 获取;私人套装;}
公共 RankingAndIncludeSeo()
{
KeyWordsSeoList = new List();
SiteIncludeCountList = new List();
}
///
/// 当 关键词 查询完成时回调委托
///
公共操作 OnComplatedAnyKeyWordsSearch { 获取;放; }
///
/// 完成收录次网站的查询后回调delegate
///
公共操作 OnComplatedAnySiteIncludeSearch { 获取;放; }
///
/// 查询URL的排名
///
///
关键词组
///
查询网址
///
最大等级数
public void SearchKeyWordsRanking(IEnumerable 关键字,字符串 siteurl,长计数 = 100)
{
如果(关键字 == 空)
throw new ArgumentNullException("keywords", "必须存在 关键词");
如果(网站网址 == 空)
throw new ArgumentNullException("siteurl", "必须存在 网站URL");
foreach(KeyWordsSeoList 中的 KeyWordsSeoBase kwsb)
{
kwsb.OnComplatedOneKeyWord = kwsb.OnComplatedOneKeyWord ?? OnComplatedAnyKeyWordsSearch;
kwsb.SearchRanking(关键字,站点网址,计数);
}
}
///
/// 收录 查询 URL 的数量
///
///
查询网址
公共无效 SearchSiteIncludeCount(字符串网站网址)
{
如果(网站网址 == 空)
throw new ArgumentNullException("siteurl", "必须指定 网站");
foreach(SiteIncludeCountBase sicb 中的 SiteIncludeCountList)
{
sicb.OnComplatedOneSite = sicb.OnComplatedOneSite ?? OnComplatedAnySiteIncludeSearch;
sicb.SearchIncludeCount(siteurl);
}
}
}
RankingAndIncludeSeo 提供了一个公共代表。如果单个搜索引擎不提供委托,则使用此公共委托。如果指定了单独的delegate,就不会分配了,其他开发者只需要在调用时添加到KeyWordsSeoList和SiteIncludeCountList中已经实现的类即可,其他开发者自己开发实现加入即可。
七、部分
一般来说,这篇文章不是关于高端技术的,而只是提供一个大致的想法和结构设计。如果读者需要在实际开发中应用,最好验证一下。作者不保证关键词的排名没有错误,因为搜索结果可能因任何因素而发生变化。
^.^我是源代码下载