导师的一篇论文需要用到包含某一个关键字Github上的代码片段,所以我写了一个爬虫项目将github上面包含某一关键字的代码链接全部爬取出来,并存入csv文件中。
python版本:python 3.6
开发用的IDE:pycharm
所用的第三方库: 爬虫:requests + BeautifulSoup
github官方API: https://developer.github.com/v3/search/#search-code //这是官方的API用来搜索,得到的是一个Json文件//
本来的想法是直接用github官方的API直接得到一个JSON文件然后再去解析,但是13年以后,search-code的这个API就不能在全部的公共库中去搜索,搜索时,必须要指定特定的用户或者机构或者是项目库。这个是它的官方说明: https://developer.github.com/changes/2013-10-18-new-code-search-requirements/
所以要换一个思路,我的想法是先用爬虫爬取所有包含某写关键字代码的库名和作者名,然后用这些库名和某一关键字作为参数去调用github的官方API,通过解析返回的JSON文档,得到相关代码的链接和一些其他的信息。
def parse_keyword(self, keyword):
# 解析登陆以后的页面,筛选出包含这个关键字的python代码
user_repositorys = set() # 集合用来存放作者名和库名
for i in range(101): #github上只显示前一百页的信息
url = "https://github.com/search?l=Python&p={id}&q={keyword}&type=Code".format(id=i+1, keyword=keyword) # 循环的爬取页面信息
#需要登录验证
resp = self.session.get(url=url, headers=self.login_headers, verify=False)
soup = BeautifulSoup(resp.text, "lxml")#解析信息
#通过标签可以筛序信息
pattern = soup.find_all('a', class_='text-bold')
for item in pattern: #将库名和作者名存入集合之中
print(item.string)
user_repositorys.add(item.string)
上面代码主要是有两个问题要解决,第一个是github上爬取公共库需要登录验证,我参考的是这位作者的方法:https://blog.csdn.net/killeri/article/details/86093665
代码如下:
class github_crawl(): def __init__(self): # 初始化一些必要的参数 self.login_headers = { "Referer": "https://github.com/", "Host": "github.com", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } self.logined_headers = { "Referer": "https://github.com/login", "Host": "github.com", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } self.login_url = "https://github.com/login" self.post_url = "https://github.com/session" self.session = requests.Session() def parse_loginPage(self): # 对登陆页面进行爬取,获取token值 html = self.session.get(url=self.login_url, headers=self.login_headers, verify=False) Soup = BeautifulSoup(html.text, "lxml") token = Soup.find("input", attrs={"name": "authenticity_token"}).get("value") return token # 获得了登陆的一个参数 def login(self, user_name, password): # 传进必要的参数,然后登陆 post_data = { "commit": "Sign in", "utf8": "✓", "authenticity_token": self.parse_loginPage(), "login": user_name, "password": password } } logined_html = self.session.post(url=self.post_url, data=post_data, headers=self.logined_headers, verify=False) if logined_html.status_code == 200: self.parse_keyword() # 调用parse_keyword,获得关于这个关键字的库名 if __name__ == "__main__": x = github_crawl() x.login("user", "password")
第二问题是,是找到网页中关于作者和库名显示的标签
这个问题比较好解决:
不难发现,他的html的特点,所以用soup.findall函数:
pattern = soup.find_all('a', class_='text-bold')
到此为止,我们就已经把包含某个关键字的的库名全部爬取下来了。
得到了包含某个关键字的库名以后,我们就可是使用github的官方API了,他的官方API使用起来非常方便,就是一个网页链接的形式,构造好了以后,就会返回一个json文件。例如:
https://api.github.com/search/code?q=df.applymap+in:file+language:python+repo:rvpatel92/HW3
//表示在rvpatel92/HW3这个库里面包含df.applymap这个关键字的代码片段
把这个网址输进去,得到结果如下,剩下的工作就是解析这个json文件
代码如下
def get_results(self, repository, keyword): # 用Github的官方API爬取数据,解析json
url = "https://api.github.com/search/code?q={keyword}+in:file+language:python+repo:{w}".format(w=repository, keyword=keyword)#只是搜索语言为python的代码
req = Request(url, headers=self.headers) #需要token认证
response = urlopen(req).read()
results = json.loads(response.decode())
for item in results['items']:
repo_url = item["repository"]["html_url"]#得到项目库的链接
file_path = item['html_url']#得到代码的链接
fork = item["repository"]["fork"]#是否引用
self.loader_csv(repo_url, file_path, fork, keyword)
def loader_csv(self, repo_url, file_path, fork, keyword): #写入csv文件
with open("F:\\task\\github.csv", "a") as csv_file:
writer = csv.writer(csv_file)
writer.writerow([keyword, repo_url, file_path])
csv_file.close()
到此整个项目的任务算是完成了。
class github_crawl():
def __init__(self):
# 初始化一些必要的参数
self.login_headers = {
"Referer": "https://github.com/",
"Host": "github.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
}
self.logined_headers = {
"Referer": "https://github.com/login",
"Host": "github.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
}
self.headers = {
'User-Agent': 'Mozilla/5.0',
'Authorization': 'token 80531720f7835b5861e87812aa773256086498d6',#换上自己的token认证
'Content-Type': 'application/json',
'Accept': 'application/json'
}
self.login_url = "https://github.com/login"
self.post_url = "https://github.com/session"
self.session = requests.Session()
def parse_loginPage(self):
# 对登陆页面进行爬取,获取token值
html = self.session.get(url=self.login_url, headers=self.login_headers, verify=False)
Soup = BeautifulSoup(html.text, "lxml")
token = Soup.find("input", attrs={"name": "authenticity_token"}).get("value")
return token
# 获得了登陆的一个参数
def login(self, user_name, password,keyword):
# 传进必要的参数,然后登陆
post_data = {
"commit": "Sign in",
"utf8": "✓",
"authenticity_token": self.parse_loginPage(),
"login": user_name,
"password": password
}
logined_html = self.session.post(url=self.post_url, data=post_data, headers=self.logined_headers, verify=False)
if logined_html.status_code == 200:
self.parse_keyword(keyword) # 获取了页面
def parse_keyword(self, keyword):
# 解析登陆以后的页面,筛选出包含这个关键字的python代码
user_repositorys = set() # 集合用来存放作者名和库名
try:
for i in range(101):
url = "https://github.com/search?l=Python&p={id}&q={keyword}&type=Code".format(id=i+1, keyword=keyword) # 循环的爬取页面信息
resp = self.session.get(url=url, headers=self.login_headers, verify=False)
soup = BeautifulSoup(resp.text, "lxml")
pattern = soup.find_all('a', class_='text-bold')
for item in pattern:
user_repositorys.add(item.string)
for user_repository in user_repositorys:
self.get_results(user_repository, keyword)
except Exception as e:
print(e)
def get_results(self, repository, keyword): # 用Github的官方API爬取数据,解析json
url = "https://api.github.com/search/code?q={keyword}+in:file+language:python+repo:{w}".format(w=repository, keyword=keyword)
try:
req = Request(url, headers=self.headers)
response = urlopen(req).read()
results = json.loads(response.decode())
for item in results['items']:
repo_url = item["repository"]["html_url"]
file_path = item['html_url']
fork = item["repository"]["fork"]
self.loader_csv(repo_url, file_path, fork, keyword)
except Exception as e:
print("获取失败")
def loader_csv(self, repo_url, file_path, keyword):
try:
with open("path", "a") as csv_file:
writer = csv.writer(csv_file)
writer.writerow([keyword, repo_url, file_path])
csv_file.close()
except Exception as e:
print(e)
if __name__ == "__main__":
x = github_crawl()
x.login("user", "password","keyword")