阅读更多

14顶
2踩

编程语言

原创新闻 基于Spindle的增强HTTP Spider

2008-04-01 11:48 by 见习记者 brunoplum 评论(8) 有18204人浏览
   构建于lucene之上的可用的Java开源Spider少之又少,spindle长期没有更新且功能不够完善,故而自己参考其源
代码重新编写了一个可扩展的WebCrawler,本着开源共享,共同进步的想法发布于此,期冀得到大家的批评指正,
有任何意见及建议均可Email联系我 (kaninebruno@hotmail.com)
   以下代码基于lucene-2.3.1,htmlparser-1.6,je-analysis-1.5.3,以及自己修改过的cpdetector-1.0.5;
下载地址分别为
htmlparser:http://sourceforge.net/project/showfiles.php?group_id=24399
je-analysis:http://www.jesoft.cn/je-analysis-1.5.3.jar
lucene就不用说了,cpdetector-1.0.5见附件.
spindle的官方站点:http://www.bitmechanic.com/projects/spindle/
package com.huizhi.kanine.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;

import jeasy.analysis.MMAnalyzer;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.htmlparser.Parser;
import org.htmlparser.PrototypicalNodeFactory;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.tags.BaseHrefTag;
import org.htmlparser.tags.FrameTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.MetaTag;
import org.htmlparser.util.EncodingChangeException;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;

import cpdetector.io.ASCIIDetector;
import cpdetector.io.CodepageDetectorProxy;
import cpdetector.io.JChardetFacade;
import cpdetector.io.ParsingDetector;
import cpdetector.io.UnicodeDetector;


/**
 * @author 张波 
 * E-mail:kaninebruno@hotmail.com 
 * Created On : 2008-03-30
 */
public class SiteCapturer implements Runnable{
	
	/* 基准(初始)URL */
	protected URL mSource;

	/* 索引文件的存放位置 */
	protected String mTarget;

	/**
	 * 待解析的URL地址集合,所有新检测到的链接均存放于此;
	 * 解析时按照先入先出(First-In First-Out)法则线性取出
	 */
	protected ArrayList mPages;

	/* 已解析的URL地址集合,避免链接的重复抓取 */
	protected HashSet mFinished;

	protected Parser mParser;
	
	/* StringBuffer的缓冲区大小 */
	protected  final int TRANSFER_SIZE = 4096;
	
	/* 当前平台的行分隔符 */
	protected static String lineSep = System.getProperty("line.separator");
	
	/* 程序运行线程数,默认2个线程 */
	protected int mthreads;
	
	protected ArrayList threadList;
	
	/* 存储于磁盘的IndexWriter */
	protected IndexWriter FSDWriter;
	
	/* 存储于内存的IndexWriter */
	protected IndexWriter RAMWriter;

	protected IndexSearcher indexSearcher;

	protected RAMDirectory ramDirectory;
	
	/* 筛选页面内容的分词器 */
	protected Analyzer luceneAnalyzer;

	/* 解析页面时的字符编码 */
	protected String charset;
	
	/* 统计已抓取的页面数量 */
	protected int count = 0;
	
	/* 基准端口 */
	protected int mPort;
	
	/* 基准主机 */
	protected String mHost;
	
	/* 检测索引中是否存在当前URL信息,避免重复抓取 */
	protected boolean mCheck;

	/* 索引操作的写入线程锁 */
	public static final Object indexLock = new Object();
	
	public SiteCapturer() {
		mSource = null;
		mTarget = null;
		mthreads = 2;
		mCheck = false;
		mPages = new ArrayList();
		mFinished = new HashSet();
		mParser = new Parser();
		PrototypicalNodeFactory factory = new PrototypicalNodeFactory();
		factory.registerTag(new LocalLinkTag());
		factory.registerTag(new LocalFrameTag());
		factory.registerTag(new LocalBaseHrefTag());
		mParser.setNodeFactory(factory);
	}

	public String getSource() {
		return mSource.toString();
	}

	public void setSource(String source) {
		if (source.endsWith("/"))
			source = source.substring(0, source.length() - 1);
		try {
			mSource = new URL(source);
		} catch (MalformedURLException e) {
			System.err.println("Invalid URL : " + getSource());
		}
	}

	public String getTarget() {
		return (mTarget);
	}

	public void setTarget(String target) {
		mTarget = target;
	}
	
	public int getThreads() {
		return (mthreads);
	}

	public void setThreads(int threads) {
		mthreads = threads;
	}
	
	public boolean isMCheck() {
		return mCheck;
	}

	public void setMCheck(boolean check) {
		mCheck = check;
	}

	/**
	 * 程序入口,在此初始化mPages、IndexWriter
	 * 通过协调各线程间的活动完成website的抓取工作
	 * 任务完成后将所有的索引片段合并为一个以优化检索
	 */
	public void capture(){

		mPages.clear();
		mPages.add(getSource());
		
		int responseCode = 0;
		String contentType = "";
		
		try {
			HttpURLConnection uc = (HttpURLConnection) mSource.openConnection();
			responseCode = uc.getResponseCode();
			contentType = uc.getContentType();
		} catch (MalformedURLException mue) {
			System.err.println("Invalid URL : " + getSource());
		} catch (IOException ie) {
			if (ie instanceof UnknownHostException) {
				System.err.println("UnknowHost : " + getSource());
			} else if (ie instanceof SocketException) {
				System.err.println("Socket Error : " + ie.getMessage() + " "
						+ getSource());
			} else
				ie.printStackTrace();
		}
		
		if (responseCode == HttpURLConnection.HTTP_OK
				&& contentType.startsWith("text/html")) {
			
			mPort = mSource.getPort();
			mHost = mSource.getHost();
			charset = autoDetectCharset(mSource);

			/* 存放索引文件的位置 */
			File indexDir = new File(mTarget);
			/* 标记是否重新建立索引,true为重新建立索引 */
			boolean flag = true;
			if (!indexDir.exists()) {
				/* 如果文件夹不存在则创建 */
				indexDir.mkdir();
			} else if (IndexReader.indexExists(mTarget)) {
				/* 如果已存在索引,则追加索引 */
				flag = false;
				File lockfile = new File(mTarget + File.separator + "write.lock");
				if (lockfile.exists())
					lockfile.delete();
			}
			luceneAnalyzer = new MMAnalyzer();
			ramDirectory = new RAMDirectory();

			try {
				FSDWriter = new IndexWriter(indexDir, luceneAnalyzer, flag);
				RAMWriter = new IndexWriter(ramDirectory, luceneAnalyzer, true);
				
				while (mCheck) {
					IndexReader indexReader = IndexReader.open(mTarget);
					indexSearcher = new IndexSearcher(indexReader);
				}
				
				long start = System.currentTimeMillis();
				threadList = new ArrayList();

				for (int i = 0; i < mthreads; i++) {
					Thread t = new Thread(this, "K-9 Spider Thread #" + (i + 1));
					t.start();
					threadList.add(t);
				}
				while (threadList.size() > 0) {
					Thread child = (Thread) threadList.remove(0);
					try {
						child.join();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				long elapsed = System.currentTimeMillis() - start;

				RAMWriter.close();
				FSDWriter.addIndexes(new Directory[] { ramDirectory });
				FSDWriter.optimize();
				FSDWriter.close();

				System.out.println("Finished in " + (elapsed / 1000)
						+ " seconds");
				System.out.println("The Count of the Links Captured is "
						+ count);
			} catch (CorruptIndexException cie) {
				cie.printStackTrace();
			} catch (LockObtainFailedException lofe) {
				lofe.printStackTrace();
			} catch (IOException ie) {
				ie.printStackTrace();
			}
		}	 
	}
	
	public void run() {
		String url;
		while ((url = dequeueURL()) != null) {
			if (isToBeCaptured(url))
				process(url);
		}
		mthreads--;
	}

	/**
	 * 判断提取到的链接是否符合解析条件;标准为Port及Host与基准URL相同且类型为text/html或text/plain
	 */
	public boolean isToBeCaptured (String url){
		boolean flag = false;
		
		HttpURLConnection uc = null;
		int responseCode = 0;
		String contentType = "";
		String host = "";
		int port = 0;
		
		try {
			URL source = new URL(url);
			String protocol = source.getProtocol();
			if (protocol != null && protocol.equals("http")) {
				host = source.getHost();
				port = source.getPort();
				uc = (HttpURLConnection) source.openConnection();
				uc.setConnectTimeout(8000);
				responseCode = uc.getResponseCode();
				contentType = uc.getContentType();
			}
		} catch (MalformedURLException mue) {
			System.err.println("Invalid URL : " + url);
		} catch (IOException ie) {
			if (ie instanceof UnknownHostException) {
				System.err.println("UnknowHost : " + url);
			} else if (ie instanceof SocketException) {
				System.err.println("Socket Error : " + ie.getMessage() + " "
						+ url);
			} else if (ie instanceof SocketTimeoutException) {
				System.err.println("Socket Connection Time Out : " + url);
			} else if (ie instanceof FileNotFoundException) {
				System.err.println("broken link "
						+ ((FileNotFoundException) ie.getCause()).getMessage()
						+ " ignored");
			} else
				ie.printStackTrace();
		}
		
		if (port == mPort
				&& responseCode == HttpURLConnection.HTTP_OK
				&& host.equals(mHost)
				&& (contentType.startsWith("text/html") || contentType
						.startsWith("text/plain")))
			flag = true;
		return flag;
	}

	/* 从URL队列mPages里取出单个的URL */
	public synchronized String dequeueURL() {
		while (true) {
			if (mPages.size() > 0) {
				String url = (String) mPages.remove(0);
				mFinished.add(url);
				
				if (isToBeCaptured(url)) {
					int bookmark;
					NodeList list;
					NodeList robots;
					MetaTag robot;
					String content;
					try {
						bookmark = mPages.size();
						/* 获取页面所有节点 */
						mParser.setURL(url);
						try {
							list = new NodeList();
							for (NodeIterator e = mParser.elements(); e
									.hasMoreNodes();)
								list.add(e.nextNode());
						} catch (EncodingChangeException ece) {
							/* 解码出错的异常处理 */
							mParser.reset();
							list = new NodeList();
							for (NodeIterator e = mParser.elements(); e
									.hasMoreNodes();)
								list.add(e.nextNode());
						}
						/**
						 * 依据 http://www.robotstxt.org/wc/meta-user.html 处理
						 * Robots  tag
						 */
						robots = list
								.extractAllNodesThatMatch(
										new AndFilter(new NodeClassFilter(
												MetaTag.class),
												new HasAttributeFilter("name",
														"robots")), true);
						if (0 != robots.size()) {
							robot = (MetaTag) robots.elementAt(0);
							content = robot.getAttribute("content")
									.toLowerCase();
							if ((-1 != content.indexOf("none"))
									|| (-1 != content.indexOf("nofollow")))
								for (int i = bookmark; i < mPages.size(); i++)
									mPages.remove(i);
						}
					} catch (ParserException pe) {
						pe.printStackTrace();
					}
				}
				return url;
			} else {
				mthreads--;
				if (mthreads > 0) {
					try {
						wait();
						mthreads++;
					} catch (InterruptedException ie) {
						ie.printStackTrace();
					}
				} else {
					notifyAll();
					return null;
				}
			}
		}
	}

	/**
	 * 处理单独的URL地址,解析页面并加入到lucene索引中;通过自动探测页面编码保证抓取工作的顺利执行
	 */
	protected void process(String url) {
		
		String result[];
		String content = null;
		String title = null;

		/* 此项操作较耗性能,故默认不予检测 */
		if (mCheck) {
			try {
				TermQuery query = new TermQuery(new Term("url", url));
				Hits hits = indexSearcher.search(query);
				if (hits.length() > 0) {
					System.out.println("The URL : " + url
							+ " has already been captured");
				} else {
					result = parseHtml(url, charset);
					content = result[0];
					title = result[1];
				}
			} catch (IOException ie) {
				ie.printStackTrace();
			}
		} else {
			result = parseHtml(url, charset);
			content = result[0];
			title = result[1];
		}
		
		if (content != null && content.trim().length() > 0) {

			Document document = new Document();
			document.add(new Field("content", content, Field.Store.YES,
					Field.Index.TOKENIZED,
					Field.TermVector.WITH_POSITIONS_OFFSETS));
			document.add(new Field("url", url, Field.Store.YES,
					Field.Index.UN_TOKENIZED));
			document.add(new Field("title", title, Field.Store.YES,
					Field.Index.TOKENIZED,
					Field.TermVector.WITH_POSITIONS_OFFSETS));
			document.add(new Field("date", DateTools.timeToString(new Date()
					.getTime(), DateTools.Resolution.DAY), Field.Store.YES,
					Field.Index.UN_TOKENIZED));
			
			synchronized (indexLock) {
				try {
					RAMWriter.addDocument(document);
					/**
					 * 当存放索引的内存使用大于指定值时将其写入硬盘;采用此方法的目的是
                     * 通过内存缓冲避免频繁的IO操作,提高索引创建性能;
                     */
					if (RAMWriter.ramSizeInBytes() > 512 * 1024) {
						RAMWriter.close();
						FSDWriter.addIndexes(new Directory[] { ramDirectory });
						RAMWriter = new IndexWriter(ramDirectory,
								luceneAnalyzer, true);
					}
					count++;
					System.out.println(Thread.currentThread().getName()
							+ ": Finished Indexing URL: " + url);
				} catch (CorruptIndexException cie) {
					cie.printStackTrace();
				} catch (IOException ie) {
					ie.printStackTrace();
				}
			}
		}
	}

	/**
	 * Link tag that rewrites the HREF.
	 * The HREF is changed to a local target if it matches the source.
	 */
	class LocalLinkTag extends LinkTag {
		public void doSemanticAction() {

			String link = getLink();
			if (link.endsWith("/"))
				link = link.substring(0, link.length() - 1);
			int pos = link.indexOf("#");
			if (pos != -1)
				link = link.substring(0, pos);

			/* 将链接加入到处理队列中 */
			if (!(mFinished.contains(link) || mPages.contains(link)))
				mPages.add(link);

			setLink(link);
		}
	}

	/**
	 * Frame tag that rewrites the SRC URLs. The SRC URLs are mapped to local
	 * targets if they match the source.
	 */
	class LocalFrameTag extends FrameTag {
		public void doSemanticAction() {

			String link = getFrameLocation();
			if (link.endsWith("/"))
				link = link.substring(0, link.length() - 1);
			int pos = link.indexOf("#");
			if (pos != -1)
				link = link.substring(0, pos);

			/* 将链接加入到处理队列中 */
			if (!(mFinished.contains(link) || mPages.contains(link)))
				mPages.add(link);

			setFrameLocation(link);
		}
	}

	/**
	 * Base tag that doesn't show. The toHtml() method is overridden to return
	 * an empty string, effectively shutting off the base reference.
	 */
	class LocalBaseHrefTag extends BaseHrefTag {
		
		public String toHtml() {
			return ("");
		}
	}
	
	/* 自动探测页面编码,避免中文乱码的出现 */
	protected String autoDetectCharset(URL url) {
		
		CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
		/**
		 * ParsingDetector可用于检查HTML、XML等文件或字符流的编码
		 * 构造方法中的参数用于指示是否显示探测过程的详细信息
		 * 为false则不显示
		 */ 
		detector.add(new ParsingDetector(false));
		detector.add(JChardetFacade.getInstance());
		detector.add(ASCIIDetector.getInstance());
		detector.add(UnicodeDetector.getInstance());
		
		Charset charset = null;
		try {
			charset = detector.detectCodepage(url);
		} catch (MalformedURLException mue) {
			mue.printStackTrace();
		} catch (IOException ie) {
			ie.printStackTrace();
		}
		if (charset == null)
			charset = Charset.defaultCharset();
		return charset.name();
	}

	/* 按照指定编码解析标准的html页面,为建立索引做准备*/
	protected String[] parseHtml(String url, String charset) {

		String result[] = null;
		String content = null;
		
		try {
			URL source = new URL(url);
			InputStream in = source.openStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					in, charset));
			String line = new String();
			StringBuffer temp = new StringBuffer(TRANSFER_SIZE);
			while ((line = reader.readLine()) != null) {
				temp.append(line);
				temp.append(lineSep);
			}
			reader.close();
			in.close();
			content = temp.toString();
		} catch (MalformedURLException mue) {
			System.err.println("Invalid URL : " + url);
		} catch (UnsupportedEncodingException uee) {
			uee.printStackTrace();
		} catch (IOException ie) {
			if (ie instanceof UnknownHostException) {
				System.err.println("UnknowHost : " + url);
			} else if (ie instanceof SocketException) {
				System.err.println("Socket Error : " + ie.getMessage() + " "
						+ url);
			} else if (ie instanceof SocketTimeoutException) {
				System.err.println("Socket Connection Time Out : " + url);
			} else
				ie.printStackTrace();
		}

		if (content != null) {
			Parser myParser = Parser.createParser(content, charset);
			HtmlPage visitor = new HtmlPage(myParser);
			try {
				myParser.visitAllNodesWith(visitor);
				String body = null;
				String title = "Untitled";
				if (visitor.getBody() != null) {
					NodeList nodelist = visitor.getBody();
					body = nodelist.asString().trim();
				}
				if (visitor.getTitle() != null)
					title = visitor.getTitle();
				result = new String[] { body, title };
			} catch (ParserException pe) {
				pe.printStackTrace();
			}
		}
		return result;
	}
	
	public static void main(String[] args) {
		SiteCapturer worker = new SiteCapturer();
		
		if (args.length < 6)
			throw new IllegalArgumentException(
					"Usage:java -u [start url] -d [index dir] -t [threads] [-c]");

		for (int i = 0; i < args.length; i++) {
			if (args[i].equals("-u"))
				worker.setSource(args[++i]);
			else if (args[i].equals("-d"))
				worker.setTarget(args[++i]);
			else if (args[i].equals("-t"))
				worker.setThreads(Integer.parseInt(args[++i]));
			else if (args[i].equals("-c"))
				worker.setMCheck(true);
		}
		
		if (worker.getThreads() < 1)
			throw new IllegalArgumentException("Invalid number of threads: "
					+ worker.getThreads());
		
		worker.capture();
		System.exit(0);
	}
}

程序运行可选择控制台或新建一JSP页面,加入以下代码即可
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="com.huizhi.kanine.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lucene</title>
</head>
<body>
<%
	SiteCapturer worker = new SiteCapturer();
	worker.setSource ("http://www.blabla.cn/");
	worker.setTarget("c:\\luceneIndexes");
	worker.setThreads(20);
	worker.capture();
%>
</body>
</html>
14
2
评论 共 8 条 请登录后发表评论
8 楼 凤凰山 2009-04-19 01:03
where is
             the   cpdetector-1.0.5 
7 楼 D04540214 2008-08-17 09:45
十二哥,好像很久没有更新了哦
6 楼 ganyu21 2008-07-18 10:14
为什么没有,nutch就很好
5 楼 kokojjy 2008-06-02 17:06
太感谢楼主了
4 楼 wangpeng198245ok 2008-04-27 16:36
3 楼 lianguangpei 2008-04-23 17:14
写的真不错!
2 楼 lianguangpei 2008-04-22 18:34
楼主很伟大啊! 
1 楼 arthurwun 2008-04-02 17:53
Dear sir

  may i ask where can I find ur updated 'cpdetector-1.0.5' attachment , I can't find anything in this page , please offer
it to us, thx

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 网络爬虫

    网页爬虫汇总 Heritrix Heritrix是一个开源,可扩展的... http://crawler.archive.org/ WebSPHINX WebSPHINX是一个Java类包和Web爬虫的交互式开发环境。Web爬虫(也叫作机器人或蜘蛛)是可以自动浏览与处理Web页面的...

  • 网页爬虫汇总

    转自 网页爬虫汇总 Heritrix  Heritrix是一个开源,可扩展的web...http://crawler.archive.org/ WebSPHINX  WebSPHINX是一个Java类包和Web爬虫的交互式开发环境。Web爬虫(也叫作机器人或蜘蛛)是可以自动浏

  • 网页爬虫

    Heritrix  Heritrix是一个开源,可扩展的...http://crawler.archive.org/ WebSPHINX  WebSPHINX是一个Java类包和Web爬虫的交互式开发环境。Web爬虫(也叫作机器人或蜘蛛)是可以自动浏览与处理Web页面的程序。Web

  • 爬虫大全,爬虫工具汇总

    开源爬虫 开发语言 ...是一个基于Java的web spider框架.它包含一个简单的HTML剖析器能够分析包含HTML内容的输入流.通过实现Arachnid的子类就能够开发一个简单的Web spiders并能够在Web站上的每...

  • 针对HP-UNIX的telnet java程序 - Java - JavaEye知识库

     基于Spindle的增强HTTP Spider  构建于lucene之上的可用的Java开源Spider少之又少,spindle长期没有更新且功能不够完善,故而自己参考其源代码重新编写了一个可扩展的WebCrawler,本着开源共享,共同进步的想法发布...

  • 开源大全

    分类: IT综合技术 from :http://www.open-open.com/[@more@] ...Spring Framework 【Java开源 ...Spring 是一个解决了许多在J2EE开发中常见的问题的强大框架。...Spring的架构基础是基于使用JavaB

  • 数据集:CIFAR-10、CIFAR-100、MNIST、SVHN、ImageNet、LSUN

    "barn_spider"], "74": ["n01773797", "garden_spider"], "75": ["n01774384", "black_widow"], "76": ["n01774750", "tarantula"], "77": ["n01775062", "wolf_spider"], "78": ["n01776313", "tick"], "79": ["n...

  • pyzmq-15.1.0-py2.7-macosx-10.6-intel.egg

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

  • 51单片机库(基于12M晶振).zip

    该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

  • keke-15-cdn.mobileconfig

    keke-15-cdn.mobileconfig

  • 2024-2030年生鲜乳行业市场调研及前景趋势预测报告.pdf

    2024-2030年生鲜乳行业市场调研及前景趋势预测报告.pdf

  • 2024-2030年尼龙 66市场调研及前景趋势预测报告.pdf

    2024-2030年尼龙 66市场调研及前景趋势预测报告.pdf

  • aiohttp-3.8.0a7-cp36-cp36m-musllinux_1_1_s390x.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

  • pyzmq-25.1.2-cp38-cp38-macosx_10_9_x86_64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

  • 2024-2030年袜子行业市场调研及前景趋势预测报告.pdf

    2024-2030年袜子行业市场调研及前景趋势预测报告.pdf

  • 图书借阅系统小程序端.zip

    该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

  • 将用户添加到docker组

    linux常用命令大全

  • java课程设计:基于SpringBoot的图书馆管理系统.zip

    该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

  • pyzmq-26.0.0-cp311-cp311-musllinux_1_1_aarch64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

Global site tag (gtag.js) - Google Analytics