思路如下:
1.抓取整个网页
2.找到所有图片
3.创建线程池并发下载图片
代码如下:
public class Crawler {
//正文图片正则
static final Pattern PATTERN = Pattern.compile("<img class=\"BDE_Image\" src=\"(.*?)\"");
// 爬取百度贴吧的图片
public static void main(String[] args) throws IOException {
//贴吧地址
String url = "https://tieba.baidu.com/p/2256306796?red_tag=1781367364";
// 抓取整个网页
String html = fetch(url);
// 创建线程池,并发下载图片
ExecutorService service = Executors.newFixedThreadPool(8);
//图片正则匹配网页
Matcher matcher = PATTERN.matcher(html);
// 找到每个匹配的图片
while (matcher.find()) {
// 获取图片的路径
String imageURL = matcher.group(1);
// 提交给线程池进行下载
service.submit(() -> {
try {
download(imageURL);
} catch (IOException e) {
e.printStackTrace();
}
});
}
//关闭线程池
service.shutdown();
}
//抓取网页的html内容
private static String fetch(String url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
StringBuilder sb = new StringBuilder(1024 * 1024);
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))
) {
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
sb.append(line);
}
} catch (IOException e) {
}
return sb.toString();
}
//下载图片
private static void download(String imageURL) throws IOException {
HttpURLConnection c = (HttpURLConnection) new URL(imageURL).openConnection();
// https://imgsa.baidu.com/forum/w%3D580/sign=43e292947c1ed21b79c92eed9d6fddae/6bfab2fb43166d228b3c16f2472309f79052d20a.jpg
// 图片名
String image = imageURL.substring(imageURL.lastIndexOf("/") + 1);
try (
InputStream in = c.getInputStream();
OutputStream out = new FileOutputStream("e:\\images\\" + image)
) {
byte[] bytes = new byte[1024 * 1024];
while (true) {
int len = in.read(bytes);
if (len == -1) {
break;
}
out.write(bytes, 0, len);
}
}
}
}
从以上案例中,可以学到:
1.处理资源关闭的语法
try with resources
try(AutoCloseable 资源 = ...) {
...
} catch(Exception e) {
}
// finally块没有了
由编译器帮我们添加以下代码:
finally {
if(资源 != null) {
try {
资源.close();
} catch (Exception e) {
}
}
}
> idea中可以用.twr 快捷键添加这个语法
2.使用组匹配可以一次获取关注的内容
例如,字符串中的图片地址
<img class="样式" src="3.png">
可以使用正则来获取到组1的内容,即()内的内容
<img.*src="(.*)">
3. 贪婪,非贪婪
<img class="样式" src="3.png"> <img class="样式" src="4.png">
如果使用
<img.*src="(.*)">
匹配后组1结果是:
3.png"> <img class="样式" src="4.png
这是因为默认情况下 *, + 等量词是贪婪的(尽可能匹配更多)
需要改为非贪婪,即在量词后跟? (尽可能匹配更少)
```
<img class="样式" src="(.*?)">
```
4. 可以使用多线程提高下载效率