c#批量抓取免费代理并验证有效性
之前看到某公司的官网的文章的浏览量刷新一次网页就会增加一次,给人的感觉不太好,一个公司的官网给人如此直白的漏洞,我批量发起请求的时候发现页面打开都报错,100多人的公司的官网文章刷新一次你给我看这个,这公司以前来过我们学校宣传招人+在园子里搜招聘的时候发现居然以前招xamarin,挺好奇的,所以就关注过。好吧不说这些了,只是扯扯蛋而已,回归主题,我想说的是csdn的文章可以通过设置代理ip刷新文章的浏览量,所以首先要做的就是这篇文章的主题“使用c#验证代理ip有效性”。
当然代理IP来源肯定是免费,所以嘛效率一般,从一些免费的代理ip的网页抓取的代理IP并不一定都是有用的,所以需要我们对我们抓取的代理ip进行验证,代理ip的有效时间也是有限,从10几秒到1个小时不限,大多数时间非常短,所以比如说,我们1分钟需要100个代理ip,那就1分钟获取一次,每次获取100个(这里是理想状态下的,抓取的代理ip都是有效的),原则上来说抓取下来后应该立即马上被使用。
当然这篇文章比较基础,一直觉得爬虫比较有趣,其实我在爬虫方面也是个小白,只是做一个简单的记录,如果有什么错误的地方,希望能提出建议。针对下面几个问题,我们就可以完成如何验证代理IP有效性的检测了。
1.从哪些网页上可以抓取免费的代理IP?
百度一下“免费代理ip”挺多的。
2.代理IP稳定吗?有什么作用?
这种免费的代理ip时效性和有效性都不强,上面这三个免费的代理网站,时效性大概在十几秒到1个小时不等,一般需要自己处理验证后使用,提高命中率。可适用于隐藏网页IP(有些网站还不准使用代理ip,比如豆瓣,其实挺尴尬的,内容这么贵吗),一般常用于空间留言、刷网站流量、网赚任务、批量注册账号等,只要没有其他限制,需要频繁更换ip都可以使用。
3.ping通IP就是有效的吗?如何验证代理是否有效
好吧,这有点废话,进行端口测试才是最有效的,能ping通并不代表代理有效,不能平通也不一定代理不可用。可以使用HttpWebRequest,也可以使用Scoket,当然HttpWebRequest比Socket连接代理ip、port要慢。
4.一次提取多少代理合适?
代理ip时效性不强、并且有效性也不高,所以只能从一些代理ip的网站上批量定时去获取,有的代理在一分钟内使用是有限制的,所以说限制比较多。
5.http代理和https代理有什么区别?
需要访问https的网站就需要使用https代理了,比如百度,需要访问http的代理,可以使用http。这个并不是100%的。
检测代理ip有效性步骤如下:
1.使用HttpWebRequest、HttpWebResponse请求代理ip的网页,获取包含代理的网页内容
2.使用HtmlAgilityPack或者正则表达式对抓取的内容进行截取,保存到代理集合
3.拿到代理集合,多线程发起http请求,比如访问百度,是否成功,成功则存到Redis里面。
效果图如下:
使用HttpWebRequest发起请求
Request.cs如下,主要就是两个方法,一个方法是验证代理ip是否有效,设置HttpWebRequest的Proxy属性,请求百度,看到有些文章大多数会获取响应的内容,如果内容符合请求的网址则证明代理哟有效,实际上根据HttpStatusCode 200就可以判断是否验证有效。
【注意】建的是控制台程序,使用了异步,所以还是建.net core吧,c#语言的版本7.1。C#如何在控制台程序中使用异步
public class Request
{
/// <summary>
/// 验证代理ip有效性
/// </summary>
/// <param name="proxyIp">代理IP</param>
/// <param name="proxyPort">代理IP 端口</param>
/// <param name="timeout">详情超时</param>
/// <param name="url">请求的地址</param>
/// <param name="success">成功的回调</param>
/// <param name="fail">失败的回调</param>
/// <returns></returns>
public static async System.Threading.Tasks.Task getAsync(string proxyIp,int proxyPort, int timeout,string url, Action success, Action<string> fail)
{
System.GC.Collect();
HttpWebRequest request = null;
HttpWebResponse response = null;
try
{
request = (HttpWebRequest)WebRequest.Create(url);
//HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.Timeout =timeout;
request.KeepAlive = false;
request.Proxy = new WebProxy(proxyIp,proxyPort);
response = await request.GetResponseAsync() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
success();
}
else
{
fail(response.StatusCode+":"+response.StatusDescription);
}
}
catch (Exception ex)
{
fail("请求异常"+ex.Message.ToString());
}
finally
{
if (request != null)
{
request.Abort();
request = null;
}
if (response != null)
{
response.Close();
}
}
} /// <summary>
/// 发起http请求
/// </summary>
/// <param name="url"></param>
/// <param name="success">成功的回调</param>
/// <param name="fail">失败的回调</param>
public static void get(string url,Action<string> success,Action<string> fail)
{
StreamReader reader = null;
Stream stream = null;
WebRequest request = null;
HttpWebResponse response = null;
try
{
request = WebRequest.Create(url);
request.Timeout = ;
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
stream = response.GetResponseStream();
reader = new StreamReader(stream);
string result = reader.ReadToEnd();
success(result);
}
else
{
fail(response.StatusCode+":"+response.StatusDescription);
}
}
catch (Exception ex)
{
fail(ex.ToString());
}
finally
{
if (reader != null)
reader.Close();
if (stream != null)
stream.Close();
if(response!=null)
response.Close();
if(request!=null)
request.Abort();
}
}
}
抓取免费代理,并检查是否有效
ProxyIpHelper.cs 中主要有四个方法,检查ip是否可用CheckProxyIpAsync、抓取xicidaili.com的代理GetXicidailiProxy、抓取ip3366.net的代理GetIp3366Proxy、抓取66ip.cn的代理GetIp3366Proxy。如果想多抓取几个网站可以多写几个。
public class ProxyIpHelper
{
private static string address_xicidaili = "http://www.xicidaili.com/wn/{0}";
private static string address_66ip = "http://www.66ip.cn/nmtq.php?getnum=20&isp=0&anonymoustype=0&start=&ports=&export=&ipaddress=&area=1&proxytype=1&api=66ip";
private static string address_ip3366 = "http://www.ip3366.net/?stype=1&page={0}";
/// <summary>
/// 检查代理IP是否可用
/// </summary>
/// <param name="ipAddress">ip</param>
/// <param name="success">成功的回调</param>
/// <param name="fail">失败的回调</param>
/// <returns></returns>
public static async Task CheckProxyIpAsync(string ipAddress, Action success, Action<string> fail)
{
int index = ipAddress.IndexOf(":");
string proxyIp = ipAddress.Substring(, index);
int proxyPort = int.Parse(ipAddress.Substring(index + ));
await Request.getAsync(proxyIp, proxyPort, , "https://www.baidu.com/", () =>
{
success();
}, (error) =>
{
fail(error);
});
}
/// <summary>
/// 从xicidaili.com网页上去获取代理IP,可以分页
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
public static List<string> GetXicidailiProxy(int page)
{
List<string> list = new List<string>();
for (int p = ; p <= page; p++)
{
string url = string.Format(address_xicidaili, p);
Request.get(url,(docText)=> {
if (!string.IsNullOrWhiteSpace(docText))
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(docText);
var trNodes = doc.DocumentNode.SelectNodes("//table[@id='ip_list']")[].SelectNodes("./tr");
if (trNodes != null && trNodes.Count > )
{
for (int i = ; i < trNodes.Count; i++)
{
var tds = trNodes[i].SelectNodes("./td");
string ipAddress = tds[].InnerText + ":" + int.Parse(tds[].InnerText); ;
list.Add(ipAddress);
}
}
}
},(error)=> {
Console.WriteLine(error);
});
}
return list;
}
/// <summary>
/// 从ip3366.net网页上去获取代理IP,可以分页
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
public static List<string> GetIp3366Proxy(int page)
{
List<string> list = new List<string>();
for (int p = ; p <= page; p++)
{
string url = string.Format(address_ip3366, p);
Request.get(url, (docText) => {
if (!string.IsNullOrWhiteSpace(docText))
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(docText);
var trNodes1 = doc.DocumentNode.SelectNodes("//table")[];
var trNodes2 = doc.DocumentNode.SelectNodes("//table")[].SelectSingleNode("//tbody");
var trNodes = doc.DocumentNode.SelectNodes("//table")[].SelectSingleNode("//tbody").SelectNodes("./tr");
if (trNodes != null && trNodes.Count > )
{
for (int i = ; i < trNodes.Count; i++)
{
var tds = trNodes[i].SelectNodes("./td");
if (tds[].InnerHtml == "HTTPS")
{
string ipAddress = tds[].InnerText + ":" + int.Parse(tds[].InnerText); ;
list.Add(ipAddress);
}
}
}
}
}, (error) => {
Console.WriteLine(error);
});
}
return list;
}
/// <summary>
/// 从66ip.cn中去获取,不需要分页
/// </summary>
/// <returns></returns>
public static List<string> Get66ipProxy()
{
List<string> list = new List<string>();
Request.get(address_66ip,
(docText)=> {
int count = ;
if (string.IsNullOrWhiteSpace(docText) == false)
{
string regex = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\:\\d{1,5}";
Match mstr = Regex.Match(docText, regex);
while (mstr.Success && count < )
{
string tempIp = mstr.Groups[].Value;
list.Add(tempIp);
mstr = mstr.NextMatch();
count++;
}
}
},
(error)=> {
Console.WriteLine(error);
});
return list;
}
}
使用Timer定时抓取,并检查,成功则保存到redis
c#有三种定时器,这里定时器是使用System.Threading命名空间, 这个Timer会开启新的线程,抓取三个网页定义了三个Timer对象。每一次抓取都会保存上一次抓取的集合,检查前,会进行对比,取出新的集合也就是没有重复的那部分。有效性的ip比较低,这里没有做统计,如果代码再优化一下,可以做一下统计,看看程序的主入口吧,最终的实现如下:
class Program
{
static bool timer_ip3366_isCompleted = true;
static bool timer_xicidaili_isCompleted = true;
static bool timer_66ip_isCompleted = true;
static Timer timer_ip3366, timer_xicidaili, timer_66ip;
private static List<string> lastListip3366,lastList66ip,lastListxicidaili;//保存上一次抓取的代理,与下一次进行对比,取新的集合进行检查筛选
static async Task Main(string[] args)
{
System.Net.ServicePointManager.DefaultConnectionLimit = ;
Console.WriteLine("hellow proxyIp");
Console.ReadLine();
lastList66ip = new List<string>();
lastListip3366 = new List<string>();
lastListxicidaili = new List<string>();
timer_ip3366 = new Timer(async (state) =>
{
await TimerIp3366Async();
}, "processing timer_ip3366 event", ,*);
timer_xicidaili = new Timer(async (state) =>
{
await TimerXicidailiAsync();
}, "processing timer_xicidaili event", , * );
timer_66ip = new Timer(async (state) =>
{
await Timer66ipAsync();
}, "processing timer_66ip event", , *); Console.ReadLine();
} private static async Task Timer66ipAsync()
{
if (timer_66ip_isCompleted)
{
timer_66ip_isCompleted = false;
List<string> checkList = new List<string>();
var listProxyIp = ProxyIpHelper.Get66ipProxy(); if (listProxyIp.Count > )
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("66ip.cn 抓取到" + listProxyIp.Count + "条记录,正在对比.........");
listProxyIp.ForEach(f =>
{
if (!lastList66ip.Contains(f))
{
checkList.Add(f);
}
});
lastList66ip = listProxyIp;
if (checkList.Count > )
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("66ip.cn 需要检查" + checkList.Count + "条记录,正在进行检测是否有效..........");
for (int i = ; i < checkList.Count; i++)
{
string ipAddress = checkList[i];
await ProxyIpHelper.CheckProxyIpAsync(ipAddress, () =>
{
bool insertSuccess = RedisHelper.InsertSet(ipAddress);
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("66ip.cn");
if (insertSuccess)
{
Console.WriteLine("success" + ipAddress + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
}
Console.WriteLine("重复插入" + ipAddress + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
}, (error) =>
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("66ip.cn");
Console.WriteLine("error:" + ipAddress + error + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
});
}
timer_66ip_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("66ip.cn" + checkList.Count + "条记录,已经检测完成,正在进行下一次检查");
}
else
{
timer_66ip_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("66ip.cn没有需要检查的代理ip");
}
}
else
{
timer_66ip_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("66ip.cn没有获取到代理ip");
}
}
} private static async Task TimerXicidailiAsync()
{
if (timer_xicidaili_isCompleted)
{
//取出需要检查的ip地址,第一次100条则checklist就是100条记录,
//第二次的100条中只有10是和上一次的不重复,则第二次只需要检查这10条记录
timer_xicidaili_isCompleted = false;
List<string> checkList = new List<string>();
var listProxyIp = ProxyIpHelper.GetXicidailiProxy();
if (listProxyIp.Count > )
{
Console.WriteLine("xicidaili.com 抓取到" + listProxyIp.Count + "条记录,正在对比............");
listProxyIp.ForEach(f =>
{
if (!lastListxicidaili.Contains(f))
{
checkList.Add(f);
}
});
lastListxicidaili = listProxyIp;
if (checkList.Count > )
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("xicidaili.com 需要检查" + checkList.Count + "条记录,正在进行检测是否有效..........");
for (int i = ; i < checkList.Count; i++)
{
string ipAddress = checkList[i];
await ProxyIpHelper.CheckProxyIpAsync(ipAddress, () =>
{
bool insertSuccess = RedisHelper.InsertSet(ipAddress);
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("xicidaili.com");
if (insertSuccess)
{
Console.WriteLine("success" + ipAddress + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
}
else
Console.WriteLine("重复插入" + ipAddress + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
}, (error) =>
{
Console.WriteLine("xicidaili.com");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("error:" + ipAddress + error + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
});
}
timer_xicidaili_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("xicidaili.com" + checkList.Count + "条记录,已经检测完成,正在进行下一次检查");
}
else
{
timer_xicidaili_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("xicidaili.com没有需要检查的代理ip");
}
}
else
{
timer_xicidaili_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("xicidaili.com没有获取到代理ip");
}
}
}
private static async Task TimerIp3366Async()
{
if (timer_ip3366_isCompleted)
{
timer_ip3366_isCompleted = false;
List<string> checkList = new List<string>();
var listProxyIp = ProxyIpHelper.GetIp3366Proxy();
if (listProxyIp.Count > )
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("ip3366.net 抓取到" + listProxyIp.Count + "条记录,正在进行检测是否有效..........");
listProxyIp.ForEach(f =>
{
if (!lastListip3366.Contains(f))
{
checkList.Add(f);
}
});
lastListip3366 = listProxyIp;
if (checkList.Count != )
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("ip3366.net 需要检查" + checkList.Count + "条记录,正在进行检测是否有效..........");
for (int i = ; i < checkList.Count; i++)
{
string ipAddress = checkList[i];
await ProxyIpHelper.CheckProxyIpAsync(ipAddress, () =>
{
bool insertSuccess = RedisHelper.InsertSet(ipAddress);
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("ip3366.net");
if (insertSuccess)
{
Console.WriteLine("success" + ipAddress + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("重复插入" + ipAddress + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
}
}, (error) =>
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("ip3366.net");
Console.WriteLine("error " + ipAddress + "任务编号:" + i + "当前任务线程:" + Thread.CurrentThread.ManagedThreadId);
});
}
timer_ip3366_isCompleted = true;
Console.WriteLine("ip3366.net" + checkList.Count + "条记录,已经检测完成,正在进行下一次检查");
}
else
{
timer_ip3366_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("ip3366.net没有需要检查的代理ip");
}
}
else
{
timer_ip3366_isCompleted = true;
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("ip3366.net没有获取到代理ip");
} }
}
}
Redis第三库使用的stackoverflow的 StackExchange.Redis,代理ip不能重复储存,所以采用的数据结构是Set。存的值非常简单就一个ip加上port,也可以存入更多相关信息,感觉没必要。即使有这些其他的信息,也很难发挥作用。RedisHelper.cs如下
public class RedisHelper
{
private static readonly object Locker = new object();
private static ConnectionMultiplexer _redis;
private const string CONNECTTIONSTRING = "127.0.0.1:6379,DefaultDatabase=3";
public const string REDIS_SET_KET_SUCCESS = "set_success_ip";
private static ConnectionMultiplexer Manager
{
get
{
if (_redis == null)
{
lock (Locker)
{
if (_redis != null) return _redis;
_redis = GetManager();
return _redis;
}
}
return _redis;
}
}
private static ConnectionMultiplexer GetManager(string connectionString = null)
{
if (string.IsNullOrEmpty(connectionString))
{
connectionString = CONNECTTIONSTRING;
}
return ConnectionMultiplexer.Connect(connectionString);
}
public static bool InsertSet(string value)
{
var db = Manager.GetDatabase();
return db.SetAdd(REDIS_SET_KET_SUCCESS,value);
}
}
总结
明天补上刷新网页浏览量的文章吧,代码还不够好,ip的有效性还不高,对多线程的使用还不是很熟练
7月6号的补充:完成csdn刷文章的浏览量了:C#使用代理Ip刷新csdn文章浏览量
c#批量抓取免费代理并验证有效性的更多相关文章
- C#多线程爬虫抓取免费代理IP
这里用到一个HTML解析辅助类:HtmlAgilityPack,如果没有网上找一个增加到库里,这个插件有很多版本,如果你开发环境是使用VS2005就2.0的类库,VS2010就使用4.0,以此类推.. ...
- python爬虫批量抓取ip代理
使用爬虫抓取数据时,经常要用到多个ip代理,防止单个ip访问太过频繁被封禁.ip代理可以从这个网站获取:http://www.xicidaili.com/nn/.因此写一个python程序来获取ip代 ...
- vb.net 多线程爬虫抓取免费代理IP
Class Program Public Shared masterPorxyList As List(Of proxy) = New List(Of proxy)() Public Class pr ...
- 【转】Python 代码批量抓取免费高清图片!
import requests from bs4 import BeautifulSoup import random import time from fake_useragent import U ...
- 使用HtmlAgilityPack批量抓取网页数据
原文:使用HtmlAgilityPack批量抓取网页数据 相关软件点击下载登录的处理.因为有些网页数据需要登陆后才能提取.这里要使用ieHTTPHeaders来提取登录时的提交信息.抓取网页 Htm ...
- day36 08-Hibernate抓取策略:批量抓取
package cn.itcast.test; import java.util.List; import org.hibernate.Hibernate; import org.hibernate. ...
- Python3利用BeautifulSoup4批量抓取站点图片的代码
边学边写代码,记录下来.这段代码用于批量抓取主站下所有子网页中符合特定尺寸要求的的图片文件,支持中断. 原理很简单:使用BeautifulSoup4分析网页,获取网页<a/>和<im ...
- Web自动化框架LazyUI使用手册(4)--控件抓取工具Elements Extractor详解(批量抓取)
概述 前面的一篇博文详细介绍了单个控件抓取的设计思路&逻辑以及使用方法,本文将详述批量控件抓取功能. 批量抓取:打开一个web页面,遍历页面上所有能被抓取的元素,获得每个元素的iframe.和 ...
- 如何上传Packages到PyPI并批量抓取
1.如何上传包到PyPI ? 更新中... 2.批量抓取simple网站第三方模块 https://pypi.python.org/simple/ 3. 第三方模块的安装和使用 python set ...
随机推荐
- 如何确保API的安全性
目标: 定义API安全性要求 使用security scheme来应用资源和方法级策略 定义API的自定义security scheme 将OAuth2.0外部供应商策略应用到资源方法 为API定义一 ...
- ASP.NET MVC中的路由IRouteConstraint方法应用实例
在如下代码的写法中: public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { ro ...
- Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin【Finchley 版】
Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin[Finchley 版] 发表于 2018-04-24 | 随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请 ...
- cocos2d-x工作小记
1.当一个layer跳到下一个layer时,需要传递数据,可以默认定义一个setUserData()方法. 2.cocos2d-x不使用传统的值类型,所有的对象都创建在堆上,然后通过指针引用. 3.传 ...
- arcis api for js 值 3.17 本地部署
1. 引言 在学习 ArcGIS API 的过程中,如果我们引用在线的 API,在没有网络或者网络差的情况下,会影响到我们的学习效率,本篇文章就是为了解决这个问题.下载 ArcGIS API 之后,部 ...
- Python_字符串连接
#join() 与split()相反,join()方法用来将列表中多个字符串进行连接,并在相邻两个字符串之间插入指定字符 li=['apple','peach','banana','pear'] se ...
- 第二章之S5PV210在BL1中点亮LED灯
1,u-boot中第一个入口在./arch/arm/cpu/armv7/start.S 翻到153行:如下图 前面都是进行一些基本设置,不用管. cpu_init_cp15设置协处理器, cpu_in ...
- scrapy中 Mongo的存储
import pymongo MONGO_HOST = 'localhost' MONGO_PORT = 27017 MONGO_DB = 'today' MONGO_COLL = 'mm' clas ...
- 实验效果展示(会声会影+FSCapture)
第一步,视频录制: 利用屏幕录制软件(Eg:FSCapture,可设定矩形区域)录制信号采集过程,存储. 第二步,视频叠加制作 1)导入视频 2)主轨,复叠轨视频安插&时序调整 3)两个视频图 ...
- MySql常用两大存储引擎简介
MyISAM存储引擎简介 MyISAM存储引擎的表在数据库中,每一个表都被存放为三个以表名命名的物理文件. 首先肯定会有任何存储引擎都不可缺少的存放表结构定义信息的.frm文件,另外还有.MYD和.M ...