| @@ -5,6 +5,7 @@ Contains all website/framework-specific Class crawlers. | |||
| """ | |||
| import logging | |||
| import math | |||
| import time | |||
| import threading | |||
| @@ -78,7 +79,7 @@ class GitHubCrawler(threading.Thread): | |||
| queue_percent_full))) | |||
| repo_names = [repo["full_name"] for repo in resp.json()] | |||
| repo_stars = self._get_repositories_stars(repo_names) | |||
| repo_ranks = self._get_repository_ranks(repo_names) | |||
| for repo in resp.json(): | |||
| while self.clone_queue.full(): | |||
| @@ -86,7 +87,7 @@ class GitHubCrawler(threading.Thread): | |||
| self.clone_queue.put(indexer.GitRepository( | |||
| repo["html_url"], repo["full_name"].replace("/", ""), | |||
| "GitHub", repo_stars[repo["full_name"]])) | |||
| "GitHub", repo_ranks[repo["full_name"]])) | |||
| if int(resp.headers["x-ratelimit-remaining"]) == 0: | |||
| time.sleep(int(resp.headers["x-ratelimit-reset"]) - | |||
| @@ -98,25 +99,25 @@ class GitHubCrawler(threading.Thread): | |||
| if sleep_time > 0: | |||
| time.sleep(sleep_time) | |||
| def _get_repositories_stars(self, repo_names): | |||
| def _get_repository_ranks(self, repo_names): | |||
| """ | |||
| Return the number of stargazers for several repositories. | |||
| Return the ranks for several repositories. | |||
| Queries the GitHub API for the number of stargazers for any given | |||
| repositories, and blocks if the query limit is exceeded. | |||
| repositories, and blocks if the query limit is exceeded. The rank is | |||
| calculated using these numbers. | |||
| :param repo_names: An array of repository names, in | |||
| `username/repository_name` format. | |||
| :type repo_names: str | |||
| :return: A dictionary with repository name keys, and corresponding | |||
| stargazer count values. | |||
| :return: A dictionary mapping repository names to ranks. | |||
| Example dictionary: | |||
| .. code-block:: python | |||
| { | |||
| "user/repository" : 100 | |||
| "user/repository" : 0.2564949357461537 | |||
| } | |||
| :rtype: dictionary | |||
| @@ -125,7 +126,7 @@ class GitHubCrawler(threading.Thread): | |||
| API_URL = "https://api.github.com/search/repositories" | |||
| REPOS_PER_QUERY = 25 | |||
| repo_stars = {} | |||
| repo_ranks = {} | |||
| for names in [repo_names[ind:ind + REPOS_PER_QUERY] for ind in | |||
| xrange(0, len(repo_names), REPOS_PER_QUERY)]: | |||
| query_url = "%s?q=%s" % (API_URL, | |||
| @@ -147,14 +148,15 @@ class GitHubCrawler(threading.Thread): | |||
| time.sleep(sleep_time) | |||
| for repo in resp.json()["items"]: | |||
| rank = float(repo["stargazers_count"]) / 1000 | |||
| repo_stars[repo["full_name"]] = rank if rank < 1.0 else 1.0 | |||
| stars = repo["stargazers_count"] | |||
| rank = min(math.log(max(stars, 1), 5000), 1.0) | |||
| repo_ranks[repo["full_name"]] = rank | |||
| for name in repo_names: | |||
| if name not in repo_stars: | |||
| repo_stars[name] = 0.5 | |||
| if name not in repo_ranks: | |||
| repo_ranks[name] = 0.1 | |||
| return repo_stars | |||
| return repo_ranks | |||
| class BitbucketCrawler(threading.Thread): | |||
| """ | |||
| @@ -225,7 +227,8 @@ class BitbucketCrawler(threading.Thread): | |||
| try: | |||
| watchers = requests.get( | |||
| repo["links"]["watchers"]["href"]) | |||
| rank = len(watchers.json()["values"]) / 100 | |||
| num = len(watchers.json()["values"]) | |||
| rank = min(math.log(max(num, 1), 500), 1.0) | |||
| except requests.ConnectionError: | |||
| err = "API %s call failed:" % next_api_url | |||
| self._logger.exception(err) | |||
| @@ -233,8 +236,7 @@ class BitbucketCrawler(threading.Thread): | |||
| continue | |||
| self.clone_queue.put(indexer.GitRepository( | |||
| clone_url, repo["full_name"], "Bitbucket"), | |||
| rank if rank < 1.0 else 1.0) | |||
| clone_url, repo["full_name"], "Bitbucket"), rank) | |||
| next_api_url = response["next"] | |||
| time.sleep(0.2) | |||