用python根据关键字爬取Github上包含某关键字的代码链接

0.项目背景

导师的一篇论文需要用到包含某一个关键字Github上的代码片段,所以我写了一个爬虫项目将github上面包含某一关键字的代码链接全部爬取出来,并存入csv文件中。

1.开发环境和工具模块

python版本:python 3.6

开发用的IDE:pycharm

所用的第三方库: 爬虫:requests + BeautifulSoup

                          github官方API: https://developer.github.com/v3/search/#search-code  //这是官方的API用来搜索,得到的是一个Json文件//

2.开发思路

本来的想法是直接用github官方的API直接得到一个JSON文件然后再去解析,但是13年以后,search-code的这个API就不能在全部的公共库中去搜索,搜索时,必须要指定特定的用户或者机构或者是项目库。这个是它的官方说明:            https://developer.github.com/changes/2013-10-18-new-code-search-requirements/  

  所以要换一个思路,我的想法是先用爬虫爬取所有包含某写关键字代码的库名和作者名,然后用这些库名和某一关键字作为参数去调用github的官方API,通过解析返回的JSON文档,得到相关代码的链接和一些其他的信息。

3.项目分析

    3.1  获取包含某关键字代码的库名

	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')

到此为止,我们就已经把包含某个关键字的的库名全部爬取下来了。

 3.2 调用github上的官方API

得到了包含某个关键字的库名以后,我们就可是使用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()
	

到此整个项目的任务算是完成了。

4.项目完整代码

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")

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章