随着反爬的技术深入,特别是有关验证码返回,这对与初学者来说无疑是遇到了悬崖,原本想开开心心的登录某个网站并爬取自己需要的信息,可没想到有些网站当你在某一段时间连续登陆几次之后他就返回验证码验证一下是不是人工所为,这对于初学者来说无疑是拨了一盘冷水,网站之所以这样做无非就是防止爬虫爬取他的信息,那么作为爬虫的开发者,我们就是使用爬虫去爬去他的信息,也就是说我们爬虫者是时时刻刻都在和个站站长斗智斗勇;好了,说了那么多,我们开始进入正题吧:今天的任务就是 登录豆瓣之后爬取里面的个人发布过的日记信息-日记标题、标题链接、发布时间、日记内容等
在开始之前,我们先了解下当遇到验证码时,在实际项目中我们有哪些处理方式,直说了,一般有三种方式:
1) 手动输入验证码
2) 通过编写程序自动识别验证码-(这里会涉及到人工智能的图像识别)
3) 通过一些打码接口实现,比如打码兔等平台,让别人通过接口帮我们输入验证码,但是需要支付一定的费用
在此,我们将以第一种方式进行讲解案例的使用,首先,我们来到豆瓣官网的登录界面:https://accounts.douban.com/login?alias=&redir=https%3A%2F%2Fwww.douban.com%2F&source=index_nav&error=1001,此时不同浏览器会有不同的提示,如果有一行提示语点击“登录”超链接即可来到登录页面,然后输入一个错误的账户(为了看到深层的登录链接以及登录参数),效果图如下:
从这个效果图中显示没有验证码,这很正常,因为网站只有怀疑我们是爬虫时才返回的,然后我们把隐藏的post请求的连接复制一份粘贴到网址中访问,此时可能会出现有验证码的登录页面,然后查看源码会有以下效果图:
接着我们输入一个正确的用户名和密码以及验证码(注意:此时是需要开发开发者模式的),成功登陆之后我们找到 post 请求的链接并点击,如图:
我们登陆成功后会自动跳转到主页,其链接为:https://www.douban.com/people/178279892/,效果图如下:
因为我们待会儿需要跳转到日记页面中获取发布过的日记信息,因此我们必须想办法获取上图中的日记页面链接,经过观察,我们可以通过 xpath 表达式获取:
//a[@id="usr-profile-nav-notes"]/@href
先观察到这里,接下来我们先创建一个爬虫项目先,使用创建的命令为:scrapy startproject doubanloginproject
然后基于 basic 模板创建一个爬虫文件,命令为: scrapy genspider -t basic doubanspider douban.com
首先我们打开 items.py 定义我们需要存放数据的变量:
import scrapy
class DoubanloginprojectItem(scrapy.Item):
name = scrapy.Field() #日记标题
href = scrapy.Field() #日记标题链接
time = scrapy.Field() #日记发布时间
content = scrapy.Field() #日记内容
根据以上效果图的分析,我们开始编写我们的爬虫文件:
# -*- coding: utf-8 -*-
import scrapy
import urllib.request
# from scrapy.http import FormRequest
from doubanloginproject.items import DoubanloginprojectItem
#知乎-会话:https://www.zhihu.com/question/54773510
class DbloginspiderSpider(scrapy.Spider):
name = 'dbloginspider'
allowed_domains = ['douban.com']
start_urls = ['https://accounts.douban.com/login']
def parse(self, response):
#首先获取验证图片地址并复制给 imgurl 变量
imgurl = response.xpath('//img[@id="captcha_image"]/@src').extract()
#由于验证码时有时无,因此需要判断如果有就手动输入
if len(imgurl) > 0:
print("有验证码返回...")
#将验证图片保存到本地中
local_path = r"C:/Users/Administrator/Desktop/yanzhangma/lcy.png"
urllib.request.urlretrieve(imgurl[0], filename=local_path)
#定义接受验证码变量
capt_value = input("请查看本地 lcy.png 图片并输入对应的验证码-> ")
#设置带有验证码的 post 信息
data = {
"redir":"https://www.douban.com/people/178279892/",#要跳转的链接
"form_email":"12345678@163.com",#用户名
"form_password":"luchangyin",#密码
"captcha-solution":capt_value,#验证码
}
else:#此时不需要验证码
print("无验证码登录...")
#设置无验证码请求的参数
data = {
"redir":"https://www.douban.com/people/178279892/",#要跳转的链接
"form_email":"12345678@163.com",#用户名
"form_password":"luchangyin",#密码
}
print("登录中......")
#带参的登录请求
return [scrapy.FormRequest.from_response(response,
#设置 cookie 信息 注:这两项在 settings.py 文件中设置即可
#meta={"cookiejar":response.meta["cookiejar"]}, #如果重写 start_requests()方法,那么该值必须对应请求里的 meta 中的键
#设置请求头模拟成浏览器
#headers=self.headers,
#设置 post 表单中的数据
formdata=data,
#设置回调函数
callback=self.mynode,
)]
#之所以创建这个方法是因为如果直接打开日记链接:https://www.douban.com/people/178279892/notes 的话,不需要 cookie 也可以访问,因此为看到 cookie 的效果我们定义该方法
def mynode(self, response):
#获取用户名
my_name = response.xpath(r'//div[@class="info"]/h1/text()').extract_first()
#获取日记页面的链接
note_url = response.xpath(r'//a[@id="usr-profile-nav-notes"]/@href').extract_first()
#回调方法处理的是请求之后的数据
return scrapy.Request(note_url, callback = self.next)
到这里的话,为了验证登录之后会怎么样,建议妳在 mynode() 方法中不要就那么快的去请求日记界面链接,最好先把响应结果先存到本地的 html 中,然后打开看有木有数据,在这里我就不做演示了;接下来我们继续,看看日记页面需要怎样获取相应的信息,看图:
通过以上方法的请求跳转,我们来到了日记数据页面,根据效果图的分析结果,我们再写个方法获取日记信息:
#获取日记信息方法
def next(self, response):
print("......此时已经登录完成并爬去了个人中心的日记数据......")
#获取日记选项列表
data_list = response.xpath(r'//div[@class="note-container"]')
item = DoubanloginprojectItem() #获取实体对象
for data in data_list:
item["name"] = data.xpath(r'./div[1]/h3/a/text()').extract() #日记标题
item["href"] = data.xpath(r'./div[1]/h3/a/@href').extract() #日记链接
item["time"] = data.xpath(r'./div[1]/div/span/text()').extract()#日记发布时间
item["content"] = data.xpath(r'./div[3]/text()').extract() #日记内容
yield item
到目前为止,爬虫文件搞定了,为了以防万一,建议在循环中先输出下数据看看有木有值,这里不做演示;好了,爬虫文件搞定之后接下来我们就要对这些数据进行处理,自当来到管道文件 pipelines.py :
import csv
class DoubanloginprojectPipeline(object):
def __init__(self):
self.f = open("doubannote.csv", "w")
self.writer = csv.writer(self.f)
self.writer.writerow(['日记标题', '日记链接', '日记发布时间', '日记内容'])
def process_item(self, item, spider):
#循环写入本地文件
for i in range(0, len(item["name"])):
#保存为csv文件
dbnote_list = [item["name"][i], item["href"][i], item["time"][i], item["content"][i]]
print("管道文件测试-> %s"%dbnote_list)#输出测试
self.writer.writerow(dbnote_list)
return item
def close_spider(self, spider):
self.f.close()
最后一步,别忘了在配置文件中启动管道以及相应信息的设置哦:
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#模拟浏览器
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'
# Obey robots.txt rules 不遵循网站规则
ROBOTSTXT_OBEY = False
# Disable cookies (enabled by default) 打开 cookie,当然默认是打开的
COOKIES_ENABLED = True
#启动管道文件
ITEM_PIPELINES = {
'doubanloginproject.pipelines.DoubanloginprojectPipeline': 300,
}
万事俱备,我们开始破东风吧,执行爬虫文件:scrapy crawl dbloginspider --nolog
大致有两种提示:一种是没有验证码,一种是有验证码:
1)无验证码
2)有验证码
打开我们本地的 csv 文件:
图中可以看到爬取下来的表格中的数据后面无意中多了一个空行,只需在管道文件中修改下open()函数即可:
self.f = open("blogs.csv", "w", newline='') #newline=''去掉多余的空行