所谓道高一尺魔高一丈,爬虫和反爬虫就是矛和盾的关系,互促互进。反爬的技术手段有很多,其中封IP、注册登录、验证码等是常用的手段。爬虫这一边,对一般的情况也有应对措施,我们可以利用IP池、selenium模拟登录、机器识别验证码的方式进行爬虫。
IP池
从该网站获取IP: https://www.xicidaili.com/
selenium
selenium是什么:一个自动化测试工具(大家都是这么说的)
selenium应用场景:用代码的方式去模拟浏览器操作过程(如:打开浏览器、在输入框里输入文字、回车等),在爬虫方面很有必要
准备工作:
安装selenium(pip install selenium)
安装chromedriver(一个驱动程序,用以启动chrome浏览器,具体的驱动程序需要对应的驱动,在官网上可以找到下载地址) 基本步骤:
session和cookie
Session 是会话的意思,会话是产生在服务端的,用来保存当前用户的会话信息,而 Cookies 是保存在客户端(浏览器),有了 Cookie 以后,客户端(浏览器)再次访问服务端的时候,会将这个 Cookie 带上,这时,服务端可以通过 Cookie 来识别本次请求到底是谁在访问。
可以简单理解为 Cookies 中保存了登录凭证,我们只要持有这个凭证,就可以在服务端保持一个登录状态。
在爬虫中,有时候遇到需要登录才能访问的网页,只需要在登录后获取了 Cookies ,在下次访问的时候将登录后获取到的 Cookies 放在请求头中,这时,服务端就会认为我们的爬虫是一个正常登录用户。
具体操作方式还是在 Chrome 中按 F12 打开开发者工具,选择 Application 标签,点开 Cookies 这一栏。
Name:这个是 Cookie 的名字。一旦创建,该名称便不可更改。
Value:这个是 Cookie 的值。
Domain:这个是可以访问该 Cookie 的域名。例如,如果设置为 .jd.com ,则所有以 jd.com ,结尾的域名都可以访问该Cookie。
Max Age:Cookie 失效的时间,单位为秒,也常和 Expires 一起使用。 Max Age 如果为正数,则在 Max Age 秒之后失效,如果为负数,则关闭浏览器时 Cookie 即失效,浏览器也不会保存该 Cookie 。
Path:Cookie 的使用路径。如果设置为 /path/ ,则只有路径为 /path/ 的页面可以访问该 Cookie 。如果设置为 / ,则本域名下的所有页面都可以访问该 Cookie 。
Size:Cookie 的大小。
HTTPOnly:如果此项打勾,那么通过 JS 脚本将无法读取到 Cookie 信息,这样能有效的防止 XSS 攻击,窃取 Cookie 内容,可以增加 Cookie 的安全性。
Secure:如果此项打勾,那么这个 Cookie 只能用 HTTPS 协议发送给服务器,用 HTTP 协议是不发送的。
那么有的网站为什么这次关闭了,下次打开的时候还是登录状态呢?
这就要说到 Cookie 的持久化了,其实也不能说是持久化,就是 Cookie 失效的时间设置的长一点,比如直接设置到 2099 年失效,这样,在浏览器关闭后,这个 Cookie 是会保存在我们的硬盘中的,下次打开浏览器,会再从我们的硬盘中将这个 Cookie 读取出来,用来维持用户的会话状态。
第二个问题产生了,服务端的会话也会无限的维持下去么,当然不会,这就要在 Cookie 和 Session 上做文章了, Cookie 中可以使用加密的方式将用户名记录下来,在下次将 Cookies 读取出来由请求发送到服务端后,服务端悄悄的自己创建一个用户已经登录的会话,这样我们在客户端看起来就好像这个登录会话是一直保持的。
练习:爬取丁香园的评论
代码如下:
import requests, json, re, random,time
from bs4 import BeautifulSoup
from selenium import webdriver
# from selenium.webdriver.common.by import Byb
from lxml import etree
import pandas as pd
"""
使用selenium进行模拟登陆
1.初始化ChromDriver
2.打开163登陆页面
3.找到用户名的输入框,输入用户名
4.找到密码框,输入密码
5.提交用户信息
"""
name = '***'
passwd = '***'
driver = webdriver.Chrome('./chromedriver')
driver.get('https://www.dxy.cn/bbs/newweb/pc/post/626626#626626')
# 将窗口调整最大
driver.maximize_window()
# 休息5s
time.sleep(5)
current_window_1 = driver.current_window_handle
print(current_window_1)
button = driver.find_element_by_class_name('signInLoginin___1fnA-')
button.click()
button = driver.find_element_by_xpath("/html/body/div[@class='main']/div[@class='login-wp']/div[@class='login__tab_wp']/a[@class='login__tab j-tab']")
button.click()
password = driver.find_element_by_xpath("/html/body/div[@class='main']/div[@class='login-wp']/div[@id='j_loginTab2']/form[@id='user']/div[@class='login__content']/div[@class='login__input_wp']/div[@class='J-account-login']/div[@class='login__input'][2]/input[@class='input__btb1']")
password.send_keys(passwd)
username = driver.find_element_by_id("username")
username.send_keys(name)
submit = driver.find_element_by_xpath("/html/body/div[@class='main']/div[@class='login-wp']/div[@id='j_loginTab2']/form[@id='user']/div[@class='login__content']/div[@class='form__button']/button[@class='button']")
time.sleep(15)
submit.click()
soup = BeautifulSoup(driver.page_source,"html.parser")
reviewers = []
comments = []
for reviewer in soup.find_all(class_="userName___325ht"):
# print(reviewer.get_text(), "\n")
reviewers.append(reviewer.get_text())
# print("**************************")
for comment in soup.find_all(class_="rtfPresenterWrap___2nlwC content___2e1cy"):
# print(comment.get_text(), "\n")
comments.append(comment.get_text())
# print("**************************")
# print(dict(zip(reviewers, comments))) #有相同的答复者
bbs_dxy = pd.DataFrame([reviewers, comments]).T
bbs_dxy.rename(columns={0:'reviewer',1:'comment'},inplace=True)
print(bbs_dxy)
运行结果如下: