网页抓取是一种从网站中提取数据的技术。它允许我们从网页上收集信息并将其用于各种目的,例如数据分析、研究或构建应用程序。
在本文中,我们将探讨一个名为“GitHub主题抓取器”的Python项目,它利用网页抓取从GitHub主题页面提取信息,并检索每个主题的存储库名称和详细信息。
介绍
GitHub是一个广泛流行的托管和协作代码存储库的平台。它提供了一个名为“主题”的功能,允许用户根据特定主题或主题对存储库进行分类。GitHub主题抓取器项目自动化了这些主题的抓取过程,并检索相关的存储库信息。
项目概述
GitHub主题抓取器使用Python实现,并利用以下库:
requests
:用于发送HTTP请求以检索网页的HTML内容。BeautifulSoup
:用于解析HTML和从中提取数据的强大库。pandas
:用于数据操作和分析的多功能库,用于将抓取的数据组织成结构化格式。
让我们深入了解代码,并了解项目的每个组件如何工作。
Python脚本
import requestsfrom bs4 import BeautifulSoupimport pandas as pd
上面的代码片段导入了三个库:requests
、BeautifulSoup
和pandas
。
def topic_page_authentication(url): topics_url = url response = requests.get(topics_url) page_content = response.text doc = BeautifulSoup(page_content, 'html.parser') return doc
定义了一个名为topic_page_authentication
的函数,它以URL作为参数。
以下是代码的分解:
1. topics_url = url
:此行将提供的URL分配给变量topics_url
。此URL表示我们要验证和检索其内容的网页。
2. response = requests.get(topics_url)
:此行使用requests.get()
函数发送HTTP GET请求到topics_url
并将响应存储在response
变量中。此请求用于获取网页的HTML内容。
3. page_content = response.text
:此行从响应对象中提取HTML内容,并将其分配给page_content
变量。 response.text
属性检索响应的文本内容。
- 4.
doc = BeautifulSoup(page_content, 'html.parser')
- 此行使用
'html.parser'
解析器解析page_content
,从而创建一个可导航的对象,代表网页的HTML结构,从而创建一个名为doc
的BeautifulSoup对象。
5. return doc
:此行从函数返回BeautifulSoup对象doc
。这意味着当调用topic_page_authentication
函数时,它将返回解析的HTML内容作为BeautifulSoup对象。
此函数的目的是验证和检索由提供的URL指定的网页的HTML内容。它使用requests
库发送HTTP GET请求检索响应内容,然后使用BeautifulSoup解析它以创建可导航对象,表示网页的HTML结构。
请注意,提供的代码片段处理网页身份验证和解析的初始步骤,但不执行任何特定的抓取或数据提取任务。
def topicSraper(doc): # Extract title title_class = 'f3 lh-condensed mb-0 mt-1 Link--primary' topic_title_tags = doc.find_all('p', {'class':title_class}) # Extract description description_class = 'f5 color-fg-muted mb-0 mt-1' topic_desc_tags = doc.find_all('p', {'class':description_class}) # Extract link link_class = 'no-underline flex-1 d-flex flex-column' topic_link_tags = doc.find_all('a',{'class':link_class}) #Extract all the topic names topic_titles = [] for tag in topic_title_tags: topic_titles.append(tag.text) #Extract the descrition text of the particular topic topic_description = [] for tag in topic_desc_tags: topic_description.append(tag.text.strip()) #Extract the urls of the particular topics topic_urls = [] base_url = "https://github.com" for tags in topic_link_tags: topic_urls.append(base_url + tags['href']) topics_dict = { 'Title':topic_titles, 'Description':topic_description, 'URL':topic_urls } topics_df = pd.DataFrame(topics_dict) return topics_df
定义了一个名为 topicScraper
的函数,该函数以一个 BeautifulSoup 对象 (doc
) 作为参数。
以下是代码的详细说明:
1. title_class = 'f3 lh-condensed mb-0 mt-1 Link--primary'
: 此行定义了包含网页上主题标题的 HTML 元素的 CSS 类名称 (title_class
)。
2. topic_title_tags = doc.find_all('p', {'class':title_class})
: 此行使用 BeautifulSoup 对象的 find_all()
方法查找所有具有指定 CSS 类 (title_class
) 的 HTML 元素 (<p>
)。 它检索一个表示主题标题标签的 BeautifulSoup 标记对象列表。
3. description_class = 'f5 color-fg-muted mb-0 mt-1'
: 此行定义了包含网页上主题描述的 HTML 元素的 CSS 类名称 (description_class
)。
4. topic_desc_tags = doc.find_all('p', {'class':description_class})
: 此行使用 find_all()
方法查找所有具有指定 CSS 类 (description_class
) 的 HTML 元素 (<p>
)。 它检索一个表示主题描述标记的 BeautifulSoup 标记对象列表。
5. link_class = 'no-underline flex-1 d-flex flex-column'
: 此行定义了包含网页上主题链接的 HTML 元素的 CSS 类名称 (link_class
)。
6. topic_link_tags = doc.find_all('a',{'class':link_class})
: 此行使用 find_all()
方法查找所有具有指定 CSS 类 (link_class
) 的 HTML 元素 (<a>
)。 它检索一个表示主题链接标记的 BeautifulSoup 标记对象列表。
7. topic_titles = []
: 此行初始化一个空列表,以存储提取的主题标题。
8. for tag in topic_title_tags: ...
: 此循环遍历 topic_title_tags
列表,并将每个标记的文本内容附加到 topic_titles
列表中。
9. topic_description = []
: 此行初始化一个空列表,以存储提取的主题描述。
10. for tag in topic_desc_tags: ...
: 此循环遍历 topic_desc_tags
列表,并将每个标记的去除空格的文本内容附加到 topic_description
列表中。
11. topic_urls = []
: 此行初始化一个空列表,以存储提取的主题 URL。
12. base_url = "https://github.com"
: 此行定义了网站的基本 URL。
13. for tags in topic_link_tags: ...
: 此循环遍历 topic_link_tags
列表,并将每个标记的 URL (基本 URL + href 属性) 连接到 topic_urls
列表中。
14. topics_dict = {...}
: 此块创建了一个包含提取数据的字典 (topics_dict
): 主题标题、描述和 URL。
15. topics_df = pd.DataFrame(topics_dict)
: 此行将 topics_dict
字典转换为 pandas DataFrame,其中每个键都成为 DataFrame 中的一列。
16. return topics_df
: 此行返回包含提取数据的 pandas DataFrame。
该函数的目的是从提供的BeautifulSoup对象(doc
)中抓取和提取信息。它从网页上特定的HTML元素中检索主题标题、描述和URL,并将它们存储在一个pandas数据框中,以便进行进一步的分析或处理。
def topic_url_extractor(dataframe): url_lst = [] for i in range(len(dataframe)): topic_url = dataframe['URL'][i] url_lst.append(topic_url) return url_lst
定义了一个名为topic_url_extractor
的函数,该函数将panda DataFrame(dataframe
)作为参数。
以下是代码的详细说明:
1. url_lst = []
:该行初始化一个空列表(url_lst
),用于存储提取的URL。
2. for i in range(len(dataframe)): ...
:该循环遍历DataFrame行的索引。
3. topic_url = dataframe['URL'][i]
:此行检索数据框中当前行索引(i
)的“URL”列的值。
4. url_lst.append(topic_url)
:此行将检索到的URL添加到url_lst
列表中。
5. return url_lst
:此行返回包含提取的URL的url_lst
列表。
该函数的目的是从提供的DataFrame的“URL”列中提取URL。
它遍历DataFrame的每一行,检索每一行的URL值,并将其添加到一个列表中。最后,该函数返回提取的URL列表。
当您想要从DataFrame中提取URL进行进一步的处理或分析(如访问每个URL或对各个网页执行其他Web抓取)时,此函数可能非常有用。
def parse_star_count(stars_str): stars_str = stars_str.strip()[6:] if stars_str[-1] == 'k': stars_str = float(stars_str[:-1]) * 1000 return int(stars_str)
定义了一个名为parse_star_count
的函数,该函数将字符串(stars_str
)作为参数。
以下是代码的详细说明:
1. stars_str = stars_str.strip()[6:]
:此行使用strip()
方法从stars_str
字符串中删除前导和尾随空格。然后从第6个字符开始切片该字符串,并将结果分配回stars_str
。此行的目的是删除字符串中的任何不需要的字符或空格。
2. if stars_str[-1] == 'k': ...
:此行检查stars_str
的最后一个字符是否为“k”,表示星级计数以千为单位。
3. stars_str = float(stars_str[:-1]) * 1000
:此行将字符串的数字部分(不包括“k”)转换为浮点数,然后乘以1000将其转换为实际的星级计数。
4. return int(stars_str)
:此行将stars_str
转换为整数并返回它。
该函数的目的是将星级计数从字符串表示形式解析并转换为整数值。它处理星级计数以千为单位(“k”)的情况,通过将字符串的数字部分乘以1000来处理。该函数将解析的星级计数作为整数返回。
当您有以字符串表示的星级计数(例如“1.2k”表示1200颗星),并且需要将它们转换为数字值以进行进一步的分析或处理时,此函数可能非常有用。
def get_repo_info(h3_tags, star_tag): base_url = 'https://github.com' a_tags = h3_tags.find_all('a') username = a_tags[0].text.strip() repo_name = a_tags[1].text.strip() repo_url = base_url + a_tags[1]['href'] stars = parse_star_count(star_tag.text.strip()) return username, repo_name, stars, repo_url
定义了一个名为get_repo_info
的函数,该函数接受两个参数:h3_tags
和star_tag
。
以下是代码的详细说明:
1. base_url = 'https://github.com'
:该行定义了GitHub网站的基本URL。
2. a_tags = h3_tags.find_all('a')
:该行使用h3_tags
对象的find_all()
方法查找其中的所有HTML元素(<a>
),并检索代表锚链接的BeautifulSoup标记对象的列表。
3. username = a_tags[0].text.strip()
:该行提取第一个锚链接标记(a_tags[0]
)的文本内容并将其分配给username
变量。它还使用strip()
方法删除任何前导或尾随空格。
4. repo_name = a_tags[1].text.strip()
:该行提取第二个锚链接标记(a_tags[1]
)的文本内容并将其分配给repo_name
变量。它还使用strip()
方法删除任何前导或尾随空格。
5. repo_url = base_url + a_tags[1]['href']
:该行从第二个锚链接标记(a_tags[1]
)检索“href”属性的值,并将其与base_url
连接起来形成存储库的完整URL。生成的URL分配给repo_url
变量。
- 6.
stars = parse_star_count(star_tag.text.strip())
- 该行提取
star_tag
对象的文本内容,删除任何前导或尾随空格,并将其作为参数传递给parse_star_count
函数。该函数返回解析后的星级数量作为整数,分配给stars
变量。
7. return username, repo_name, stars, repo_url
:该行返回一个包含提取信息的元组:username
、repo_name
、stars
和repo_url
。
该函数的目的是从提供的h3_tags
和star_tag
对象中提取有关GitHub存储库的信息。它通过浏览和提取HTML结构中的特定元素来检索用户名、存储库名称、星级计数和存储库URL。然后,该函数将此信息作为元组返回。
当您想要从包含存储库列表的网页中提取存储库信息时,该函数可能会很有用,例如在爬取GitHub主题时。
def topic_information_scraper(topic_url): #页面身份验证 topic_doc = topic_page_authentication(topic_url) #提取名称 h3_class = 'f3 color-fg-muted text-normal lh-condensed' repo_tags = topic_doc.find_all('h3', {'class':h3_class}) #获取星标签 star_class = 'tooltipped tooltipped-s btn-sm btn BtnGroup-item color-bg-default' star_tags = topic_doc.find_all('a',{'class':star_class}) #获取主题信息 topic_repos_dict = { 'username': [], 'repo_name': [], 'stars': [], 'repo_url': [] } for i in range(len(repo_tags)): repo_info = get_repo_info(repo_tags[i], star_tags[i]) topic_repos_dict['username'].append(repo_info[0]) topic_repos_dict['repo_name'].append(repo_info[1]) topic_repos_dict['stars'].append(repo_info[2]) topic_repos_dict['repo_url'].append(repo_info[3]) return pd.DataFrame(topic_repos_dict)
定义了一个名为topic_information_scraper
的函数,该函数以topic_url
作为参数。
以下是代码的详细说明:
- 1.
topic_doc = topic_page_authentication(topic_url)
- 该行调用
topic_page_authentication
函数以验证并检索topic_url
的HTML内容。解析的HTML内容分配给topic_doc
变量。
2. h3_class = 'f3 color-fg-muted text-normal lh-condensed'
:这行定义了 CSS 类名(h3_class
),用于包含主题页面中存储库名称的 HTML 元素。
3. repo_tags = topic_doc.find_all('h3', {'class':h3_class})
:这一行使用 topic_doc
对象的 find_all()
方法查找具有指定 CSS 类(h3_class
)的所有 HTML 元素(<h3>
),并检索代表存储库名称标记的 BeautifulSoup 标记对象列表。
4. star_class = 'tooltipped tooltipped-s btn-sm btn BtnGroup-item color-bg-default'
:这行定义了 CSS 类名(star_class
),用于包含主题页面中的星标计数的 HTML 元素。
5. star_tags = topic_doc.find_all('a',{'class':star_class})
:这一行使用 find_all()
方法查找具有指定 CSS 类(star_class
)的所有 HTML 元素(<a>
),并检索代表星标计数标记的 BeautifulSoup 标记对象列表。
6. topic_repos_dict = {...}
:此块创建了一个字典(topic_repos_dict
),用于存储提取的存储库信息:用户名、存储库名称、星标计数和存储库 URL。
7. for i in range(len(repo_tags)): ...
:此循环遍历 repo_tags
列表的索引,假设它与 star_tags
列表具有相同的长度。
8. repo_info = get_repo_info(repo_tags[i], star_tags[i])
:此行调用 get_repo_info
函数,以提取有关特定存储库的信息。它将当前的存储库名称标记(repo_tags[i]
)和星标计数标记(star_tags[i]
)作为参数。返回的信息分配给 repo_info
变量。
9. topic_repos_dict['username'].append(repo_info[0])
:此行将从 repo_info
中提取的用户名附加到 topic_repos_dict
中的“用户名”列表中。
10. topic_repos_dict['repo_name'].append(repo_info[1])
:此行将从 repo_info
中提取的存储库名称 repo_info
附加到 topic_repos_dict
中的“repo_name”列表中。
- 11.
topic_repos_dict['stars'].append(repo_info[2])
- 此行将从
repo_info
中提取的星标计数repo_info
附加到topic_repos_dict
中的“stars”列表中。
12. topic_repos_dict['repo_url'].append(repo_info[3])
:此行将从 repo_info
中提取的存储库 URL 附加到 topic_repos_dict
中的“repo_url”列表中。
13. return pd.DataFrame(topic_repos_dict)
:此行将 topic_repos_dict
字典转换为 pandas DataFrame,其中每个键成为 DataFrame 中的一列。生成的数据框包含提取的存储库信息。
此函数的目的是在 GitHub 上特定主题内抓取和提取存储库信息。它验证并检索主题页面的 HTML 内容,然后使用特定的 CSS 类名称提取存储库名称和星标计数。
它为每个存储库调用 get_repo_info
函数,以检索用户名、存储库名称、星标计数和存储库 URL。
提取的信息存储在字典中,然后转换为 pandas DataFrame,并由该函数返回。
if __name__ == "__main__": url = 'https://github.com/topics' topic_dataframe = topicSraper(topic_page_authentication(url)) topic_dataframe.to_csv('GitHubtopics.csv', index=None) # 根据主题创建其他 CSV 文件 url = topic_url_extractor(topic_dataframe) name = topic_dataframe['Title'] for i in range(len(topic_dataframe)): new_df = topic_information_scraper(url[i]) new_df.to_csv(f'GitHubTopic_CSV-Files/{name[i]}.csv', index=None)
代码段展示了脚本的主要执行流程。
以下是代码的详细说明:
1. if __name__ == "__main__":
:这个条件语句检查脚本是否直接运行(而不是作为模块导入)。
2. url = 'https://github.com/topics'
:这一行定义了GitHub主题页面的URL。
3. topic_dataframe = topicSraper(topic_page_authentication(url))
:这一行使用 topic_page_authentication
检索主题页面的HTML内容,然后将解析的HTML(doc
)传递给topicSraper
函数。它将结果数据帧(topic_dataframe
)分配给一个变量。
4. topic_dataframe.to_csv('GitHubtopics.csv', index=None)
:这一行将topic_dataframe
数据帧导出到名为“GitHubtopics.csv”的CSV文件中。参数index=None
确保不包括行索引。
5. url = topic_url_extractor(topic_dataframe)
:这一行调用topic_url_extractor
函数,将topic_dataframe
作为参数传递。它检索从数据帧中提取的URL列表(url
)。
6. name = topic_dataframe['Title']
:这一行从topic_dataframe
中检索“Title”列,并将其分配给变量name
。
7. for i in range(len(topic_dataframe)): ...
:此循环遍历topic_dataframe
数据帧的索引。
8. new_df = topic_information_scraper(url[i])
:这一行调用topic_information_scraper
函数,将URL(url[i]
)作为参数传递。它检索特定主题URL的存储库信息,并将其分配给new_df
数据帧。
9. new_df.to_csv(f'GitHubTopic_CSV-Files/{name[i]}.csv', index=None)
:这一行将new_df
数据帧导出到CSV文件中。文件名使用f-string动态生成,包含主题名称(name[i]
)。参数index=None
确保不包括行索引。
该脚本的目的是从GitHub主题页面中抓取和提取信息,并创建包含提取数据的CSV文件。它首先抓取主题页面,将提取的信息保存在“GitHubtopics.csv”中,然后继续使用提取的URL抓取单个主题页面。
对于每个主题,它创建一个名为该主题的新CSV文件,并在其中保存存储库信息。
可以直接执行此脚本以执行抓取并生成所需的CSV文件。
最终输出
url = 'https://github.com/topics'topic_dataframe = topicSraper(topic_page_authentication(url))topic_dataframe.to_csv('GitHubtopics.csv', index=None)
一旦运行此代码,它将生成一个名为“GitHubtopics.csv”的CSV文件,该文件看起来像这样,并且该CSV文件涵盖所有主题名称,其描述和URL。
url = topic_url_extractor(topic_dataframe) name = topic_dataframe['Title']for i in range(len(topic_dataframe)): new_df = topic_information_scraper(url[i]) new_df.to_csv(f'GitHubTopic_CSV-Files/{name[i]}.csv', index=None)
然后,此代码将执行,基于我们在之前的“GitHubtopics.csv”文件中保存的主题创建特定的csv文件。然后将这些CSV文件保存在名为“GitHubTopic_CSV-Files”的目录中,每个文件都有自己特定的主题名称。这些CSV文件看起来像这样。
这些主题csv文件存储了有关主题的一些信息,例如他们的用户名、仓库名称、仓库的星级和仓库的URL。
注意:网站的标签可能会更改,因此在运行此Python脚本之前,请根据网站检查标签。
完整脚本访问 >> https://github.com/PrajjwalSule21/GitHub-Topic-Scraper/blob/main/RepoScraper.py