gpt4 book ai didi

java - 在 Java Web 爬虫中实现线程

转载 作者:行者123 更新时间:2023-12-01 12:25:37 25 4
gpt4 key购买 nike

这是我写的原始网络爬虫:(仅供引用)

https://github.com/domshahbazi/java-webcrawler/tree/master

这是一个简单的网络爬虫,它访问给定的初始网页,从页面中抓取所有链接并将它们添加到队列(LinkedList)中,然后将它们逐个弹出并每次访问,其中循环再次开始。为了加快我的程序速度并为了学习,我尝试使用线程来实现,这样我就可以同时运行多个线程,从而在更短的时间内索引更多页面。下面是每个类:

主类

public class controller {

public static void main(String args[]) throws InterruptedException {

DataStruc data = new DataStruc("http://www.imdb.com/title/tt1045772/?ref_=nm_flmg_act_12");

Thread crawl1 = new Crawler(data);
Thread crawl2 = new Crawler(data);

crawl1.start();
crawl2.start();
}
}

爬虫类(线程)

public class Crawler extends Thread {

/** Instance of Data Structure **/
DataStruc data;

/** Number of page connections allowed before program terminates **/
private final int INDEX_LIMIT = 10;

/** Initial URL to visit **/
public Crawler(DataStruc d) {
data = d;
}

public void run() {

// Counter to keep track of number of indexed URLS
int counter = 0;

// While URL's left to visit
while((data.url_to_visit_size() > 0) && counter<INDEX_LIMIT) {

// Pop next URL to visit from stack
String currentUrl = data.getURL();

try {
// Fetch and parse HTML document
Document doc = Jsoup.connect(currentUrl)
.userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36")
.referrer("http://www.google.com")
.timeout(12000)
.followRedirects(true)
.get();

// Increment counter if connection to web page succeeds
counter++;

/** .select returns a list of elements (links in this case) **/
Elements links = doc.select("a[href]"); // Relative URL

// Add newly found links to stack
addLinksToQueue(links);

} catch (IOException e) {
//e.printStackTrace();
System.out.println("Error: "+currentUrl);
}
}
}

public void addLinksToQueue(Elements el) {
// For each element in links
for(Element e : el) {

String theLink = e.attr("abs:href"); // 'abs' prefix ensures absolute url is returned rather then relative url ('www.reddit.com/hello' rather then '/hello')

if(theLink.startsWith("http") && !data.oldLink(theLink)) {
data.addURL(theLink);
data.addVisitedURL(theLink); // Register each unique URL to ensure it isnt stored in 'url_to_visit' again
System.out.println(theLink);
}
}
}
}

DataStruc 类

public class DataStruc {

/** Queue to store URL's, can be accessed by multiple threads **/
private ConcurrentLinkedQueue<String> url_to_visit = new ConcurrentLinkedQueue<String>();

/** ArrayList of visited URL's **/
private ArrayList<String> visited_url = new ArrayList<String>();

public DataStruc(String initial_url) {
url_to_visit.offer(initial_url);
}

// Method to add seed URL to queue
public void addURL(String url) {
url_to_visit.offer(url);
}

// Get URL at front of queue
public String getURL() {
return url_to_visit.poll();
}

// URL to visit size
public int url_to_visit_size() {
return url_to_visit.size();
}

// Add visited URL
public void addVisitedURL(String url) {
visited_url.add(url);
}

// Checks if link has already been visited
public boolean oldLink(String link) {
for(String s : visited_url) {
if(s.equals(link)) {
return true;
}
}
return false;
}
}

DataStruc 是共享数据结构类,它将被 Crawler.java 线程的每个实例并发访问。 DataStruc 有一个队列来存储要访问的链接,还有一个数组列表来存储访问的 URL,以防止进入循环。我使用 ConcurrentLinkedQueue 来存储要访问的 url,因为我看到它负责并发访问。我不需要与已访问网址的数组列表进行并发访问,因为我需要做的就是添加到此列表并迭代它以检查匹配项。

我的问题是,当我比较使用单线程与使用 2 个线程(在同一 URL 上)的操作时间时,我的单线程版本似乎运行得更快。我觉得我错误地实现了线程,如果有人可以查明问题,我希望得到一些提示?

谢谢!

最佳答案

补充:看我的评论,我认为是在爬虫中检查

// While URL's left to visit
while((data.url_to_visit_size() > 0) && counter<INDEX_LIMIT) {

是错误的。由于第一个线程轮询了唯一的 URL,第二个线程将立即停止。

你可以忽略剩下的,但留给历史......

我对此类“可以并行运行的大块”的一般方法是:

  1. 使每个爬虫成为可调用的。可能Callable<List<String>>
  2. 将其提交至 ExecutorService
  3. 完成后,一次获取一个结果并将其添加到列表中。

使用此策略根本不需要使用任何并发列表。缺点是您在运行时无法获得太多实时反馈。而且,如果它们返回的内容很大,您可能需要担心内存问题。

这能满足您的需求吗?您将不得不担心 addVisitedURL所以你仍然需要它作为并发数据结构。

补充:由于您是从单个 URL 开始的,因此该策略不适用。您可以在访问第一个 URL 后应用它。

关于java - 在 Java Web 爬虫中实现线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26363585/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com