失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > python初学者爬虫教程(二)动态网页抓取

python初学者爬虫教程(二)动态网页抓取

时间:2021-10-09 23:46:10

相关推荐

python初学者爬虫教程(二)动态网页抓取

python爬虫教程(二)动态网页抓取

解析真实地址抓取通过selenium 模拟浏览器抓取selenium 安装与测试selenium爬取一条评论selenium获取文章的所有评论selenium其他操作

参考链接

目的是爬取所有评论,爬取的链接下面有提到

如果使用 AJAX 加载的动态网页,有两种方法爬取:

通过浏览器审查元素解析地址通过selenium模拟浏览器抓取

以下分别介绍两种方法:(对代码有疑问欢迎提出改进)

解析真实地址抓取

例子为参考链接中提供的网址,需要爬取网站的评论的链接

抓包。点击Network,刷新网页,评论数据就在这些文件中。一般而言,这些数据可能以 json 文件格式获取。然后找到评论数据文件,见下图。点击 Preview 即可查看数据。

爬取数据,注释有解释,执行一遍有打印测试结果。

import requestsimport jsonlink = """https://api-/v1/comments/list?callback=jQuery1124027946415311453476_1602502907332&limit=10&repSeq=4272904&requestPath=%2Fv1%2Fcomments%2Flist&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&code=&_=1602502907334"""headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'}r = requests.get(link, headers=headers)print(r.text)# 获取 json 的 stringjson_string = r.text# 将文本中的json提取出来json_string = json_string[json_string.find('{'):-2]# 测试是否提取成功print(json_string)json_data = json.loads(json_string)comment_list = json_data['results']['parents']for eachone in comment_list:message = eachone['content']print(message)

改进:这里仅仅爬取了第一页的评论,我们需要爬取所有的评论。点击不同的页码,会发现多了一些json文件

点击这些Json文件,对比他们的URL,会发现有一个参数不同:

这个参数代表的就是页码数,offset=1代表第一页。(注意:如果第一次进入,可能没有offset这个参数,因为offset默认为1,所以在URL中没有展示

根据这个原理,编写最终代码如下:

# 通过浏览器审查元素解析地址,爬取所有评论import requestsimport json# 爬取某一页的评论,link为链接def single_page_comment(link, page_number):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'}r = requests.get(link, headers=headers)# 获取 json 的 stringjson_string = r.text# 将文本中的json提取出来json_string = json_string[json_string.find('{'):-2]# 测试是否提取成功# print(json_string)json_data = json.loads(json_string)comment_list = json_data['results']['parents']print(" 第 %g 页评论:" % page_number)for eachone in comment_list:message = eachone['content']print(message)print()# 链接前半部分link1 = """https://api-/v1/comments/list?callback=jQuery1124027946415311453476_1602502907332&limit=10&offset="""# 链接后半部分link2 = """&repSeq=4272904&requestPath=%2Fv1%2Fcomments%2Flist&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&code=&_=1602502907334"""for page in range(1, 11):# 链接进行拼接,得到不同页评论的URLcurrent_link = link1 + str(page) + link2single_page_comment(current_link, page)

通过selenium 模拟浏览器抓取

在之前的方法中, 有些网站为了规避这些抓取会对地址进行加密. 因此可以用第二种方法

selenium 安装与测试

首先安装selenium 库:

pip install selenium

安装浏览器对应的geckodriver,我使用的是chrome,所以根据自己的chrome版本下载,下载地址chrome geckodriver

如果使用的是火狐,下载地址为此

其他浏览器可以百度

测试,代码如下:

from selenium import webdriver# 下载的geckodriver的存储位置driver = webdriver.Chrome(executable_path='D:\\12102\\files\\chromedriver.exe')# 自动访问的网站driver.get("/")

结果如下:

selenium爬取一条评论

修改代码,更改打开的网站:driver.get("//07/04/hello-world/")

可以定位到评论的文字:

通过下面代码来爬取该数据,注意评论在一个iframe框架下面,因此要先对iframe进行解析。因此先使用switch_to转移焦点

from selenium import webdriver# 下载的geckodriver的存储位置driver = webdriver.Chrome(executable_path='D:\\12102\\files\\chromedriver.exe')# 自动访问的网站driver.get("//07/04/hello-world/")# 错误范例,注意函数的名称,elements与element的区别# 爬取一条评论# switch_to相当于转移焦点# driver.switch_to.frame(driver.find_elements_by_css_selector("iframe[title='livere-comment']"))# comment = driver.find_elements_by_css_selector("div.reply-content")# content = comment.find_element_by_tag_name('p')# print(content.text)# 爬取一条评论# switch_to相当于转移焦点driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere-comment']"))driver.implicitly_wait(10) # 隐性等待10秒comment = driver.find_element_by_css_selector('div.reply-content')content = comment.find_element_by_tag_name('p')print(content.text)

这里添加了driver.implicitly_wait(10)隐性等待10秒,如果没有加这行代码,会报错找不到div.reply-content,因为iframe框架加载需要时间

至于driver.implicitly_wait(10)time.sleep(10)的区别,见该文章

selenium获取文章的所有评论

同样是之前的网站,这次爬取所有的评论,观察网页的结构

每页有10小页,浏览完10页后,点击下一页,总共有27页。所有用一个嵌套for循环来完成。外面一层分别表示1-10,11-20,21-27页,里面一层输出每一页的评论,每页评论输出方法同之前的爬取一条评论。

代码见下,有注释:

# selenium获取文章的所有评论from selenium import webdriver# 下载的geckodriver的存储位置driver = webdriver.Chrome(executable_path='D:\\12102\\files\\chromedriver.exe')# 自动访问的网站driver.get("//07/04/hello-world/")# 每次写文件前删除之前的内容fo = open("result.txt", "a+")fo.truncate(0)# 需要提前知道ii的范围,ii指的是需要翻几次页,在我写这个代码时,评论有27页,意味着要点两次下一页,因为每页有10小页,所以ii为range(0, 3)for ii in range(0, 3):# i指的是每页有10小页for i in range(0, 10):# 下滑到页面底部driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")# 爬取某一页的所有评论driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere-comment']"))driver.implicitly_wait(10) # 隐性等待10秒comment = driver.find_elements_by_css_selector('div.reply-content')print()print("第 %g 页评论:" % int(i + 1 + ii * 10))# 打开一个文件fo = open("result.txt", "a+")fo.write('\n')fo.write("第 %g 页评论:" % int(i + 1 + ii * 10) + '\n')# 打印所有评论for eachcomment in comment:content = eachcomment.find_element_by_tag_name('p')print(content.text)# fo.write(content.text.encode("gbk", 'ignore').decode("gbk", "ignore"))text = content.text.encode('GBK', 'ignore').decode('GBk')fo.write(text + '\n')fo.close()# 获取所有的页码按钮page_btn = driver.find_elements_by_class_name("page-btn")# 统计这一页总共有多少页评论,默认最多为10页page_btn_size = len(page_btn)if i == page_btn_size - 1:driver.switch_to.default_content()driver.implicitly_wait(10)break# 按顺序点击某一页if i != 9 and i + 1 < page_btn_size:page_btn[i + 1].click()# 把iframe又转回去,注意加上这一句driver.switch_to.default_content()# 如果网速慢,可以适当增加隐性等待时间driver.implicitly_wait(15)driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere-comment']"))# 判断页面是否有下一页的按钮,没有就退出try:next_page = driver.find_element_by_class_name("page-last-btn")next_page.click()# 把iframe又转回去,注意加上这一句driver.switch_to.default_content()driver.implicitly_wait(10)except:print()print("爬取结束!(不是爬取内容)")

selenium其他操作

自动登录

user = driver.find_element_by_name("username") #找到用户名输入框user.clear #清除用户名输入框内容user.send_keys("1234567") #在框中输入用户名pwd = driver.find_element_by_name("password") #找到密码输入框pwd.clear #清除密码输入框内容pwd.send_keys("******") #在框中输入密码driver.find_element_by_id("loginBtn").click() #点击登录

一般来说,Selenium因为要把整个网页加载出来,再开始爬取内容,速度往往较慢。但是可以用以下方法:

禁用图片,CSS,JS,如下图结果:

chrome例子:

from selenium import webdriveroptions = webdriver.ChromeOptions()# 禁用图片,CSS,JSprefs = {'profile.default_content_setting_values': {'images': 2,'permissions.default.stylesheet': 2,'javascript': 2}}options.add_experimental_option('prefs', prefs)# 下载的geckodriver的存储位置driver = webdriver.Chrome(executable_path='D:\\12102\\files\\chromedriver.exe', options=options)# 自动访问的网站driver.get("//07/04/hello-world/")

firefox例子:

# 控制 cssfrom selenium import webdriverfp = webdriver.FirefoxProfile()fp.set_preference("permissions.default.stylesheet",2)driver = webdriver.Firefox(firefox_profile=fp, executable_path = r'C:\Users\santostang\Desktop\geckodriver.exe')#把上述地址改成你电脑中geckodriver.exe程序的地址driver.get("//07/04/hello-world/")

在上述代码中,控制css的加载主要用fp = webdriver.FirefoxProfile()这个功能。设定不加载css,使用fp.set_preference(“permissions.default.stylesheet”,2)。之后使用webdriver.Firefox(firefox_profile=fp)就可以控制不加载css了。运行上述代码,得到的页面如下所示。

# 限制图片的加载from selenium import webdriverfp = webdriver.FirefoxProfile()fp.set_preference("permissions.default.image",2)driver = webdriver.Firefox(firefox_profile=fp, executable_path = r'C:\Users\santostang\Desktop\geckodriver.exe')#把上述地址改成你电脑中geckodriver.exe程序的地址driver.get("//07/04/hello-world/")

与限制css类似,限制图片的加载可以用fp.set_preference(“permissions. default.image”,2)。运行上述代码,得到的页面如图所示。

# 限制 JavaScript 的执行from selenium import webdriverfp = webdriver.FirefoxProfile()fp.set_preference("javascript.enabled", False)driver = webdriver.Firefox(firefox_profile=fp, executable_path = r'C:\Users\santostang\Desktop\geckodriver.exe')#把上述地址改成你电脑中geckodriver.exe程序的地址driver.get("//07/04/hello-world/")

如果觉得《python初学者爬虫教程(二)动态网页抓取》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。