文章目录
什么是爬虫?
爬虫就是一个HTTP客户端。当我们在浏览器地址栏输入一个URL时,浏览器就会给服务器发送一个HTTP请求,服务器接收到后会返回给浏览器一个HTTP响应。爬虫就是根据需要构造请求,并且再根据需要简单的解析一下响应数据。爬虫的优势就是可以根据需要批量的获取数据。
爬取的数据
爬取的是GitHub上项目的一些具体信息。例如:star,fork,open_issue。
然后收集这些项目的这些属性,衡量出这些项目中哪些是比较活跃/流行的。
项目最终需求
给awesome-java 这个项目中提到的所有的GitHub上的项目按照活跃程度排次序
整个项目的框架
核心工作
1.需要获取到所有待收集信息的项目列表--------基于OkHttpClient
2.遍历项目列表,一次获取到每个项目的主页信息,进一步就可以知道该项目的star,fork,open_issue--------基于Jsoup
3.把这些数据存储到数据库中--------基于MySQL
4.写一个简单网页/服务器,来展示数据库中的数据(通过图表的形式来呈现)
工作1——获取到所有待收集信息的项目列表
使用爬虫程序,获取到https://github.com/akullpp/awesome-java/blob/master/README.md这个页面的内容,进而就能知道所有的项目链接信息。
ul表示无序列表,li表示列表中的一个项,a表示超链接,a标签里的href表示链接要跳转到哪个页面。
通过分析页面结构,看到入口页面中包含很多ul,每个ul中又有很多的a标签,a标签中href属性里的url就是我们想要获取的内容。
如何获取到页面内容
构造一个HTTP请求发送给服务器即可。
通过使用OKHttp库,就能根据指定的URL获取到对应页面的内容.内容一般是一个html结构的内容。
public String getPage(String url) throws IOException {
//1.创建一个 OkHttpClient 对象
okHttpClient = new OkHttpClient();
//2.创建一个 Request 对象
//builder 这个类是一个辅助创造 Request 对象的类
// Builder 中提供的 url 方法能够设定当前请求的 url
Request request = new Request.Builder().url(url).build();
//3.创建一个call对象(负责进行一次网络访问操作)
Call call = okHttpClient.newCall(request);
//4.发送请求给服务器,获取到 response 对象;
Response response = call.execute();
//5.判定响应是否成功
if (!response.isSuccessful()) {
System.out.printf("请求失败");
return null;
}
return response.body().string();
}
如何分析页面结构
通过使用 Jsoup 库来分析网页结构,先获取所有的 li 标签。(里面混杂了一些li 标签,但是他并不是项目的内容),再获取 li 标签中的 a 标签 ,然后获取 href 的内容。存储到一个 Project 类中。
public List<Project> parseProjectList(String html) {
ArrayList<Project> result = new ArrayList<>();
Document document = Jsoup.parse(html);
Elements elements = document.getElementsByTag("li");
for (Element li : elements) {
Elements allLink = li.getElementsByTag("a");
if (allLink.size() == 0) {
//当前 li 标签没有包含 a 标签
//就直接忽略
continue;
}
Element link = allLink.get(0);
String url = link.attr("href");
if (!url.startsWith("https://github.com")) {
continue;
}
if (urlBlackList.contains(url)) {
continue;
}
Project project = new Project();
project.setName(link.text());
project.setUrl(link.attr("href"));
project.setDescription(li.text());
result.add(project);
}
return result;
}
存储项目的Project类
package dao;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Project {
//项目名称,对应 a 标签中的内容
private String name;
//项目主页链接,对应 a 标签中的 href 属性
private String url;
//项目的描述信息,对应到 li 标签里面的内容
private String description;
//以下属性都是要统计到的数据
//需要根据该项目的 url 进入到对应页面,进而统计数据
private int starCount;
private int forkCount;
private int openIssueCount;
}
通过github官方提供的API进行获取到项目的star,fork,open_issue。
通过项目的URL解析出项目仓库的仓库名和作者名
//这个方法的功能,就是把项目的 url 提取出其中的仓库名字和作者名字
public String getRepoName(String url) {
int lastOne = url.lastIndexOf("/");
int lastTwo = url.lastIndexOf("/", lastOne - 1);
if (lastOne == -1 || lastTwo == -1) {
System.out.println("当前url不是一个项目的url! url :" + url);
return null;
}
return url.substring(lastTwo + 1);
}
然后解析出仓库名和作者名后根据Github广泛提供的API,能得到一个关于此项目的一个JSON格式的文件,通过解析这个文件得到该项目的star,fork,open_issue。
public String getRepoInfo(String respName) throws IOException {
String userName = "你的Github用户名";
String passWord = "你的Github密码";
//因为github认证后你的爬取数量可以增加
//进行身份认证,把用户名密码加密之后得到一个字符串, 把这个字符串放到http header中.
String credential = Credentials.basic(userName, passWord);
String url = "https://api.github.com/repos/" + respName;
Request request = new Request.Builder().url(url).header("Authorization", credential).build();
Call call = okHttpClient.newCall(request);
Response response = call.execute();
if (!response.isSuccessful()) {
System.out.println("访问Github API失败! URL + " + url);
return null;
}
return response.body().string();
}
//通过这个方法获取到仓库相关信息
//第一个参数 jsonString 表示获取到的Github API的结果
//第二个参数 表示将解析的数据存到 project 对象里
public void parseRepoInfo(String jsonString, Project project) {
Type type = new TypeToken<HashMap<String, Object>>() {
}.getType();
HashMap<String, Object> hashMap = gson.fromJson(jsonString, type);
Double starCount = (Double)hashMap.get("stargazers_count");
project.setStarCount(starCount.