最近百度公司好像是修改了指数查询的算法,让很多网站都无法进行指数查询,比较站长站,爱站等 知名站长网站都无法查询。 在这里我使用Socket的方法来实现,也希望高手多多指点
提供源码下载:
百度指数抓取方法.zip
(88.84 KB, 下载次数: 1065)
分为这样几步,第一步是得到百度的数据,怎么得到呢? 大家起来看一下当我们查询时百度会出现什么样的数据
根据这个我现在最主的工作就是怎么样自动得到
http://index.baidu.com/gateway.php这个界面回发给我们的数据。
下面咱们来一步一步的实现吧,
在实现之后我先说一下,因为这个是从Falsh内部发起的,所以使用传统的Http请求是不可能实现的。
我们从界面上坐文章也是不可能的,因为界面上的源代码我分析过了,没有任何与之相关的内容,这点百度公司做的还是比较高明的。
但我相信只要是从我电脑上过去的东西,都有办法使用抓包的方法 来得到,
我的思路是这样的, 先使用一个WebBrowser控件把事件百度界面加载过来,
当然控件是不被呈现的,在加载这个界面进行查询的时候WebBrowser 会自动发送这些请求,也就是说我们只需要能捕获本次查询的数据就能得到我们想要的数据了。
那么我们先来定义一个WebBrowser控件吧
[C#] 纯文本查看 复制代码 //定义一个webBrowser对象用来查询百度信息
System.Windows.Forms.WebBrowser webBrowser1 = new WebBrowser();
//在加载时处理数据
private void Form1_Load(object sender, EventArgs e)
{
//加载本机的所有IP地址
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ipad in ips)
{
comboBox1.Items.Add(ipad.ToString());
}
#region 初始化webBrowser1
//出现的位置
webBrowser1.Location = new System.Drawing.Point(5, 38);
//按钮大小
webBrowser1.MinimumSize = new System.Drawing.Size(20, 20);
//对象名称
webBrowser1.Name = "webBrowser1";
//窗体大小
webBrowser1.Size = new System.Drawing.Size(855, 279);
//Tab顺序
webBrowser1.TabIndex = 5;
#endregion
}
这个时候我们只需要把数据取回来就行
怎么取呢看下面的一个方法
[C#] 纯文本查看 复制代码 private void button1_Click(object sender, EventArgs e)
{
//清空当前数据
richTextBox1.Text = "";
//存数据的变量
string userIndexes = "";
//是否开始捕获数据
F = true;
//开始查询百度信息
webBrowser1.Navigate("http://index.baidu.com/main/word.php?word=" + textBox1.Text.Trim());
//创建一个Socket对象
Socket s = new Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Raw, System.Net.Sockets.ProtocolType.IP);
//绑定IP到Socket
s.Bind(new System.Net.IPEndPoint(IPAddress.Parse(comboBox1.Text), 0));
//为当前数据报提供标头
s.SetSocketOption(System.Net.Sockets.SocketOptionLevel.IP, System.Net.Sockets.SocketOptionName.HeaderIncluded, 1);
//检查电脑所有端口
s.IOControl(unchecked((int)0x98000001), new byte[4] { 1, 0, 0, 0 }, new byte[4]);
//下面的线程只执行8秒,8秒后就不再执行了。
timer1.Enabled = true;
//开始一个新的线程,查询数据
Thread th = new Thread(delegate()
{
try
{
//确定端口 让端口唯一是为了防止多个用户同时查询时的串数据
string port = "";
//是否开始抓包
while (F)
{
//获取从网络中得到的数据,看是否有可读的数据
if (s.Available > 0)
{
//计算机所有端口
byte[] bs = new byte[65536];
//将接受到的数据存储的缓冲共里面
s.Receive(bs);
//创建一个IPIPPacket
IPPacket ip = new IPPacket(ref bs);
//只有当接发送方使用TCP协议,并且源IP为180.149.131.33时才执行
if (ip.TCP != null && ip.SourceAddress.ToString().Trim() == "180.149.131.33")
{
//将缓冲区中的数据以指定格式进行筛选,并把结果存储到Data中
string Data = System.Text.RegularExpressions.Regex.Replace(System.Text.Encoding.ASCII.GetString(ip.TCP.PacketData),
@"[^a-zA-Z_0-9\.\@\- ]", "");
//开始一次取数据时的报文端口号
if (Data.Contains("userIndexes"))
{
port = ip.TCP.DestinationPort.ToString().Trim();
}
//一次存储取出的数据
userIndexes += Data;
//当出现mediaIndexes时结束捕获
if (Data.Contains("mediaIndexes") && (port == "" || port == ip.TCP.DestinationPort.ToString().Trim()))
{
//不在捕获的标志
F = false;
//关闭自动关闭的事件
timer1.Enabled = false;
//关闭当前Socket
s.Close();
//取出userIndexes之后的数据
userIndexes = userIndexes.Substring(userIndexes.IndexOf("userIndexes"));
//取出mediaIndexes之前的数据
userIndexes = userIndexes.Substring(0, userIndexes.IndexOf("mediaIndexes") + 12);
}
//取当前流的端口
port = ip.TCP.DestinationPort.ToString().Trim();
}
}
}
//把最终取出的数据放入richTextBox1中去
if (userIndexes.Contains("mediaIndexes"))
richTextBox1.Text = userIndexes;
else
richTextBox1.Text = "数据不存在";
}
catch (Exception ex)
{
F = false;
timer1.Enabled = false;
richTextBox1.Text = ex.Message.Trim();
}
});
th.Start();
}
里面所用到的类库,大家有兴趣的话要吧问我要。
现在我们运行一个程序就能看到效果 了
当然这是加密后的数据,解密的方法这个暂时不方便 写,呵呵,还有这块技术所用到的其它类,
解密算法已过时,大家不要与我联系了,抱歉
在些也希望同行的高手能够指点一下,希望有更好的方法解决这个问题。
大家看完之后别忘记留下您的宝贵建议哦!!!
|