赞
踩
本次我们要获取的是gitee网站中搜索java得到的项目的所有评论,并将评论和回复区分开。先看看效果。
搜索的结果图是这个,看上面的链接我们通过多点击几页,发现链接中的pageno是当前的页数,q为搜索的参数。这样我们就可以更改这俩个参数获取到我所需要的所有url。
然后我们点击其中一个链接。比如下图的这个项目就有107个评论,注意结尾还有一个加载更多,它不是一次性显示出来所有评论的,需要不停的点击加载更多直到没有为止。
对于一般的评论我们获取到源码后可以很轻松的获取到,但要如何将回复和评论区分开,并将回复与该条评论放在一起呢。查看网页结构后我们发现可以通过class属性值为comment的div标签分开后,然后再在每一个div标签下提取评论,第一条评论为主评论,后面的都为该条评论的回复。
解决了这个问题后,我们还需要注意一些特殊的评论。
比如有@某人的评论,以及一些被屏蔽了的评论。这些评论的标签定位有点不一样,需要针对处理一下。
![屏幕截图 2021-05-04 011233](https://img-hello-world.oss-cn-beijing.aliyuncs.c
首先是获取搜索结果的链接。
def get_url(start,end): ''' :strart: 起始页 :end: 结束页 ''' # 获取起始页到结束页的所有项目链接 while True: try: t_url = [] h_url = 'https://search.gitee.com/?skin=rec&type=repository&q=java&pageno=' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36 Edg/89.0.774.76', } for i in range(start,end+1): new_url = h_url + str(i) print(f'正在获取第{i}页所有链接') res = requests.get(new_url,headers = headers).text # print(res) html = etree.HTML(res) x_urls = html.xpath('//div[@class="title"]/a[@class="ns" and @target="_blank"]/@href') x_urls.pop(0) # print(len(x_urls)) t_url.append({str(i):x_urls}) time.sleep(1) # print(t_url) except BaseException: print('正在重新获取该页链接') else: break return t_url
然后是获取一个链接的网页源码的函数。里面的time.sleep里的值需要根据自己的网速进行调整。
def get_html(url): #获取项目页面的源码 while True: try: #打开谷歌浏览器 wd = webdriver.Chrome() #发起请求 wd.get(url) while True: #寻找加载更多按钮进行点击 html = wd.page_source h1 = etree.HTML(html) button = h1.xpath('//div[@class="ui link button btn-load-more"]') #找不到按钮退出 if len(button) == 0: break #寻找结束按钮 later = h1.xpath('//div[@class="ui link button btn-load-more disabled"]') if len(later) == 0: #找不到结束按钮则加载更多 i = wd.find_element_by_xpath('//*[@class="ui link button btn-load-more"]') i.click() time.sleep(0.5) else: break except BaseException: wd.quit() time.sleep(0.5) print("正在重新获取") else: # 正常结束则关闭浏览器 wd.quit() time.sleep(0.5) break return html
然后是解析网页源码,提取出评论。
def get_i(lists): # 获取屏蔽评论的索引 a = [] new_lists = enumerate(lists) for new_list in new_lists: if new_list[1] == '此条评论已被系统屏蔽': a.append(new_list[0]) return a def jianxi(data): #解析xml # print(data) # 匹配出每一个大的评论块标签,包含回复 # strs = re.findall('<div class="comments"><div.*?class="comment.*?<div class="comments">|<div class="comments"><div.*?"comment note".*?</div>\n<input id',data,re.S) strs = re.findall( '<div class="comments"><div.*?data-note-id=".*?<div class="comments">|<div class="comments"><div.*?"comment note".*?</div>\n<input id', data, re.S) html = etree.HTML(data) #匹配该项目的名称 title = html.xpath('//head//meta[@itemprop="name"]/@content') #匹配该项目的评论数量 num = html.xpath('//span[@class="comments-count"]/text()') try: num = num[0].split() except IndexError: print("该项目无评论,请查看页面确认") all_data = {'title': title[0], 'comment_num': '0'} print(all_data) return all_data nu = 0 # 用于检测评论数是否正确 comments = [] #用于存储评论 if int(num[0]) != 0: for str1 in strs: # 匹配出评论者和评论时间 # print(str1) str2 = etree.HTML(str1) comments_authors = str2.xpath('//a[@class="author js-popover-card"]/text()') comments_times = str2.xpath('//span[@class="timeago"]/@title') # 匹配出一个评论和回复所在的标签 str3 = re.findall('<div class="content arrow_box".*?</div></div></div>|<div class="children-comments comments".*?</div></div></div>',str1, re.S) comments_comments = [] for str4 in str3: str5 = etree.HTML(str4) # 匹配出评论并拼接 comments_comment = str5.xpath('//p//text() | //div[@class="author blocked-title pb-2"]/text()') co = '' for com in comments_comment: co += com comments_comments.append(co) nu += 1 b = get_i(comments_comments) # 检测是否存在被系统屏蔽的评论 if len(b) != 0: comments_authors.insert(b[0], '系统屏蔽') c0 = comments_comments.pop(0) a0 = comments_authors.pop(0) t0 = comments_times.pop(0) # 检测是否存在回复 if len(comments_comments) != 0: c = [{a0: c0, 'time': t0}] d = [] for i in range(len(comments_comments)): d.append({comments_authors[i]: comments_comments[i], 'time': comments_times[i]}) c.append({'回复': d}) comments.append(c) else: comments.append([{a0: c0, 'time': t0}]) else: print('该项目无评论') #检测评论数量是否正确 if nu == int(num[0]): print(('解析正确')) else: print('解析错误') print(f'缺少{int(num[0])-nu}条评论') if num[0] != 0: all_data = {'title':title[0],'comment_num':nu,'comment':comments} else: all_data = {'title': title[0], 'comment_num': num[0]} print(all_data) return all_data
from selenium import webdriver import requests from lxml import etree import time import re def get_url(start,end): # 获取前100页的所有项目链接 while True: try: t_url = [] h_url = 'https://search.gitee.com/?skin=rec&type=repository&q=java&pageno=' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36 Edg/89.0.774.76', } for i in range(start,end+1): new_url = h_url + str(i) print(f'正在获取第{i}页所有链接') res = requests.get(new_url,headers = headers).text # print(res) html = etree.HTML(res) x_urls = html.xpath('//div[@class="title"]/a[@class="ns" and @target="_blank"]/@href') x_urls.pop(0) # print(len(x_urls)) t_url.append({str(i):x_urls}) time.sleep(1) # print(t_url) except BaseException: print('正在重新获取该页链接') else: break return t_url def get_html(url): #获取项目页面的源码 while True: try: #打开谷歌浏览器 wd = webdriver.Chrome() #发起请求 wd.get(url) while True: #寻找加载更多按钮进行点击 html = wd.page_source h1 = etree.HTML(html) button = h1.xpath('//div[@class="ui link button btn-load-more"]') #找不到按钮退出 if len(button) == 0: break #寻找结束按钮 later = h1.xpath('//div[@class="ui link button btn-load-more disabled"]') if len(later) == 0: #找不到结束按钮则加载更多 i = wd.find_element_by_xpath('//*[@class="ui link button btn-load-more"]') i.click() time.sleep(0.5) else: break except BaseException: wd.quit() time.sleep(0.5) print("正在重新获取") else: # 正常结束则关闭浏览器 wd.quit() time.sleep(0.5) break return html def get_i(lists): # 获取屏蔽评论的索引 a = [] new_lists = enumerate(lists) for new_list in new_lists: if new_list[1] == '此条评论已被系统屏蔽': a.append(new_list[0]) return a def jianxi(data): #解析xml # print(data) # 匹配出每一个大的评论块标签,包含回复 # strs = re.findall('<div class="comments"><div.*?class="comment.*?<div class="comments">|<div class="comments"><div.*?"comment note".*?</div>\n<input id',data,re.S) strs = re.findall( '<div class="comments"><div.*?data-note-id=".*?<div class="comments">|<div class="comments"><div.*?"comment note".*?</div>\n<input id', data, re.S) html = etree.HTML(data) #匹配该项目的名称 title = html.xpath('//head//meta[@itemprop="name"]/@content') #匹配该项目的评论数量 num = html.xpath('//span[@class="comments-count"]/text()') try: num = num[0].split() except IndexError: print("该项目无评论,请查看页面确认") all_data = {'title': title[0], 'comment_num': '0'} print(all_data) return all_data nu = 0 # 用于检测评论数是否正确 comments = [] #用于存储评论 if int(num[0]) != 0: for str1 in strs: # 匹配出评论者和评论时间 # print(str1) str2 = etree.HTML(str1) comments_authors = str2.xpath('//a[@class="author js-popover-card"]/text()') comments_times = str2.xpath('//span[@class="timeago"]/@title') # 匹配出一个评论和回复所在的标签 str3 = re.findall('<div class="content arrow_box".*?</div></div></div>|<div class="children-comments comments".*?</div></div></div>',str1, re.S) comments_comments = [] for str4 in str3: str5 = etree.HTML(str4) # 匹配出评论并拼接 comments_comment = str5.xpath('//p//text() | //div[@class="author blocked-title pb-2"]/text()') co = '' for com in comments_comment: co += com comments_comments.append(co) nu += 1 b = get_i(comments_comments) # 检测是否存在被系统屏蔽的评论 if len(b) != 0: comments_authors.insert(b[0], '系统屏蔽') c0 = comments_comments.pop(0) a0 = comments_authors.pop(0) t0 = comments_times.pop(0) # 检测是否存在回复 if len(comments_comments) != 0: c = [{a0: c0, 'time': t0}] d = [] for i in range(len(comments_comments)): d.append({comments_authors[i]: comments_comments[i], 'time': comments_times[i]}) c.append({'回复': d}) comments.append(c) else: comments.append([{a0: c0, 'time': t0}]) else: print('该项目无评论') #检测评论数量是否正确 if nu == int(num[0]): print(('解析正确')) else: print('解析错误') print(f'缺少{int(num[0])-nu}条评论') if num[0] != 0: all_data = {'title':title[0],'comment_num':nu,'comment':comments} else: all_data = {'title': title[0], 'comment_num': num[0]} print(all_data) return all_data if __name__ == '__main__': #jianxi(data)返回的类型为{'title':xxx,'comment_num':xxx,'comment':[[{'xxx':'xxx','time':'xxx'},{'回复':[{'xxx':'xxx','time':'xxx'}]}]]}, startTime = int(time.time()) start = 10 end = 11 p_urls = get_url(start,end) print(p_urls) for i in range(start,end+1): urls = p_urls.pop(0) # print(urls) print(f'正在获取第{i}页') j = 1 for url in urls[str(i)]: print(f'正在获取第{j}/11个项目评论') data = get_html(url) jianxi(data) j+=1 # #用于测试单个链接 # url = 'https://gitee.com/jfinal/jfinal-weixin?_from=gitee_search' # data = get_html(url) # jianxi(data) endTime = int(time.time()) differenceTime = endTime - startTime print('运行时间:' + str(differenceTime) + '秒')
这次的代码量有近200行,但只要按照流程一步步写还是没有问题的。前面所说的q参数是搜索的内容,代码里我没有加上,仅仅是对于java进行了搜索,这个有需要的话可以自己进行修改。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。