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

 

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