创建爬虫: scrapy genspider -t crawl wx_spider wxapp-union.com
使用的是craw爬虫模块
要爬取的页面
代码如下: (主要是在spiders文件中操作)
class WxSpiderSpider(CrawlSpider):
name = 'wx_spider'
allowed_domains = ['wxapp-union.com']
start_urls = ['http://www.wxapp-union.com/portal.php?mod=list&catid=2&page=1']
rules = (
Rule(LinkExtractor(allow=r'.*?portal.php?mod=list&catid=2&page=/d'), follow=True), #定义爬取规则,这个是翻页爬取,注意这里follow是需要跟进的意思 Rule(LinkExtractor(allow=r'/article-.*\d'),callback="parse_content",follow=False)
) #这个是爬取每一页里面的文章链接,此处进入文章链接后不需要再文章内跟进与爬取规则相同的链接
def parse_content(self, response):
title=response.xpath('//h1[@class="ph"]/text()').extract()
print(title)
print(response.headers)
最终爬虫将会先爬取第一页链接,再在第一页中找到个文章的链接爬取,爬取完成后在爬取第二页链接,然后爬取第二页链接内的各个文章,并以这样的顺序继续爬取
由于我们默认创建的basic spider是默认使用
start_urls里面的url
来发送get请求的,因此要发送post请求需要改写
start_requests(self)
方法
例如登录人人网
def start_requests(self):
url='http://www.renren.com/Plogin.do'
data={'email':'填入账号','password':'填入密码'}
request=scrapy.FormRequest(url=url,formdata=data,callback=self.parse_page) #构建表单请求
yield request
注意,在构建post请求时需要用到scrapy.FormRequest()
来构建请求
scrapy.FormRequest()
里面的参数formdata
表单数据不是随便填写的,而是需要在登陆的网页上找到一个提交登陆信息请求的post数据包,查看里面的formdata数据,进而能够伪造formdata数据
对于有验证码的网页可以使用PIL
库提取验证码(这里目前还没学到自动处理图片,只是把图片下载下来由人来识别),具体方法也很简单,如下:
pip install Pillow
使用 PIL
需要下载这个库
from PIL import Image
同时也需要导入一个比较方便的下载图片的模块(内置的,无需下载):from urllib.request import urlretrieve
urlretrieve('图片链接','要保存的本地地址')
Img=Image.open('打开本地保存的图片地址')
Img.show()
将图片显示出来
根据官方文档介绍,scrapy使用cookie非常简单只需要在
scrapy.Request( )
中传递一个meta={‘cookiejar’: i }
参数就行。后面的i可用是用户自行设置的参数,如数字等,下面看看它的具体用法
这里为了从一开始便维持同一个cookie会话,我改写了start_requests
用法
def start_requests(self):
yield scrapy.Request(url=self.url,meta={'cookiejar':1},callback=self.parse)
为了将这个会话维持下来,我需要在接下来的回调函数中接着带上此cookiejar
def parse(self, response):
yield scrapy.FormRequest(url=self.url,formdata=self.data,callback=self.parse_content,meta={'cookiejar':response.meta['cookiejar']})
那么这次请求的便是带上了上次此请求的cookie
那么问题来了,在使用scrapy爬取正方教务系统时,尽管使用了cookie,但是还是出现了一系列问题,这里也顺便介绍下正方教务系统的爬取方法
前期观察:由于要模拟登陆,需要在登陆页面抓包到使用post传输数据的包,找到其formdata数据并伪造即可
这是我抓到的包
可用看到我需要提交前六个数据,后面两个数据为空,现介绍前五个数据的含义
这里需要特别注意验证码图片,这是个大坑!!!
我们可以很轻易的找到图片的地址,例如这样的地址http://202.195.145.170/jndx/CheckCode.aspx(要用我们学校才能打开)
但是这里我们会发现:每次打开图片的地址,验证码都会变,并且对着图片地址刷新,验证码也会变!
这里就涉及到一个问题:你从网页上获取的图片验证码与你需要登陆使用的验证码是否一致!由于你需要使用爬虫爬取这个登陆网站两次:一次是获取爬取各个formdata
的信息,一次是使用formdata
登陆,所以必须确保两次打开的网站是同一个,也就是是同一个会话,cookie
要保持一致,这里用requests便很好解决
url = "http://202.195.144.163/jndx/default2.aspx" #教务处网站地址
s =requests.session() #建立一个会话
response =s.get(url) #此后一直使用s.get()访问此链接便能确保会话
之后的代码就很简单了:RadioButtonList1 = u"学生".encode('gb2312','replace')
#这个是固定的,‘学生’的gb2312编码
伪造好data提交的表单数据
data = {
"RadioButtonList1":RadioButtonList1,
"__VIEWSTATE":__VIEWSTATE,
"TextBox1":'学号',
"TextBox2":'密码',
"TextBox3":'验证码', #验证码使用前面提到的使用PIL提取的方法
"Button1":"",
"lbLanguage":""
}
response = s.post(url,data=data,headers=headers)
第一个坑:不要使用urlretrieve()模块来下载验证码图片!!!
urlretrieve()
不能够带cookie来访问图片,这就造成了你下载的图片不是你要登陆使用的验证码图片,其结果是得到的源码一直有验证码错误这几个字
在spider文件中写有多个回调函数时不要再一个回调函数中使用多个yield scrapy.Requests()
,因为这两个发送请求的代码不会按照你希望的顺序调用回调函数(并不是先调用写在前面的代码里面的回调函数)
在使用cookiejar
的时候最好在settings
文件中打开COOKIES_ENABLED =True
这个选项来使用cookie
接着附上spider里面的代码
# -*- coding: utf-8 -*-
#仅仅至少测试登陆的代码,比较简单
import scrapy
from PIL import Image
from urllib.request import urlretrieve
class JwcSpider(scrapy.Spider):
name = 'jwc'
data = {
"RadioButtonList1":'',
'__VIEWSTATE':'',
"TextBox1":'输入学号',
"TextBox2":'输入密码',
"TextBox3":'',
"Button1": "",
"lbLanguage": ""
}
url='http://202.195.144.168/jndx/default2.aspx/' #教务处的登陆网站
#meta用来传递cookie,cookiejar是固定表示的
def start_requests(self):
yield scrapy.Request(url=self.url,meta={'cookiejar':1},callback=self.parse)
#这个回调函数用来解析第一次请求登陆页面,获取我需要的formdata中的数据
def parse(self, response):
img_url = 'http://202.195.144.168/jndx/' + response.xpath('//img[@id="icode"]/@src').get()
value = response.xpath('//*[@id="form1"]/input/@value').get()
self.data['RadioButtonList1'] = u"学生".encode('gb2312', 'replace')
self.data['__VIEWSTATE'] = value
yield scrapy.Request(url=img_url, meta={'cookiejar':response.meta['cookiejar']}, callback=self.parse_img) #发送处理图片链接的请求时一定要带上cookie
#此回调函数用来处理验证码图片
def parse_img(self,response):
print('开始处理照片链接的响应')
with open('img.jpg','wb') as f:
f.write(response.body)
img=Image.open('img.jpg')
img.show()
self.data['TextBox3'] = input('请输入验证码:')
yield scrapy.FormRequest(url=self.url, formdata=self.data, callback=self.parse_content,meta={'cookiejar': response.meta['cookiejar']})
def parse_content(self,response):
print(response.body.decode('GB2312')) #登陆后的网页,用GB2312解码,其他方式解码的话会乱码
*此代码写的很粗糙,只是为了测试用*