参考链接
目的是爬取所有评论,爬取的链接下面有提到
如果使用 AJAX 加载的动态网页,有两种方法爬取:
以下分别介绍两种方法:(对代码有疑问欢迎提出改进)
例子为参考链接中提供的网址,需要爬取网站的评论的链接
import requests
import json
link = """https://api-zero.livere.com/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 的 string
json_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)
根据这个原理,编写最终代码如下:
# 通过浏览器审查元素解析地址,爬取所有评论
import requests
import 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 的 string
json_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-zero.livere.com/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):
# 链接进行拼接,得到不同页评论的URL
current_link = link1 + str(page) + link2
single_page_comment(current_link, page)
在之前的方法中, 有些网站为了规避这些抓取会对地址进行加密. 因此可以用第二种方法
pip install selenium
如果使用的是火狐,下载地址为此
其他浏览器可以百度
from selenium import webdriver
# 下载的geckodriver的存储位置
driver = webdriver.Chrome(executable_path='D:\\12102\\files\\chromedriver.exe')
# 自动访问的网站
driver.get("https://www.baidu.com/")
修改代码,更改打开的网站:driver.get("http://www.santostang.com/2018/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("http://www.santostang.com/2018/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)
的区别,见该文章
同样是之前的网站,这次爬取所有的评论,观察网页的结构
每页有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("http://www.santostang.com/2018/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("爬取结束!(不是爬取内容)")
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() #点击登录
chrome例子:
from selenium import webdriver
options = webdriver.ChromeOptions()
# 禁用图片,CSS,JS
prefs = {
'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("http://www.santostang.com/2018/07/04/hello-world/")
firefox例子:
# 控制 css
from selenium import webdriver
fp = 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("http://www.santostang.com/2018/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 webdriver
fp = 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("http://www.santostang.com/2018/07/04/hello-world/")
与限制css类似,限制图片的加载可以用fp.set_preference(“permissions. default.image”,2)。运行上述代码,得到的页面如图所示。
# 限制 JavaScript 的执行
from selenium import webdriver
fp = 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("http://www.santostang.com/2018/07/04/hello-world/")