爬虫就是根据URL获取网页的信息,而大部分我们想爬的网页都采用HTTP协议,所以一些相关的知识有必要了解
状态码概览如下表1,详细参见HTTP状态码对照表
表1:响应报文的状态码
状态码 | 意义 |
---|---|
1xx | 表示通知消息的,如请求收到了或者正在进行处理 |
2xx | 表示成功,如接受或知道了 |
3xx | 表示重定向,如要完成请求还必须采取进一步的行动 |
4xx | 表示客户的差错,如请求中有错误的语言或不能完成 |
5xx | 表示服务器的差错,如服务器无法完成请 |
只列出几个重要的头字段,详细参见HTTP头字段类型和HTTP头子段意义
- Host:初始URL中的主机和端口,指出请求的目的地
- User-Agent:包含客户端的浏览器与系统类型,该信息由使用的浏览器来定义,可自定义
- Connection:表示是否需要持久连接。该值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(默认进行持久连接)
- Referer:包含一个URL,用户从该URL代表的页面出发访问当前请求的页面
- Content-Length:表示请求消息正文(实体主体)的长度
- Content-Type:说明实体的文档属于什么MIME类型,或实体的内容以哪种编码格式解析,如application/xml(xml),application/json(json),application/x-www-form-urlencoded(web表单使用)
- Cookie:在HTTP服务器和用户之间传递状态信息,使网站能跟踪用户,详情往下看session的工作原理!
GET /books?name=MySQL&num=8 HTTP/1.1
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive
POST /student HTTP/1.1
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 16
Connection: Keep-Alive
name=MySQL&num=8
对登录时有验证码的系统做爬虫,cookie必须带上,虽然urllib2有自动处理cookie的办法,但是工作过程得懂
这里说的是数字、字母或数学算式验证码
1. 后台生成一些随机数字和字母后,将验证码正确答案放入session中
2. 创建图片,将随机生成的数字和字母嵌入图片;向图片加入一些干扰后,发给浏览器
3. 用户在浏览器中填写验证码后提交请求,后台将用户所填验证码与对应session中的验证码答案比对
那么问题来了,HTTP是无状态的,上述过程中,后台怎么知道对应的是哪个session,或者说是哪个用户。看一遍工作原理就懂了
1. 当客户端访问服务器时,服务器根据需求设置session,此时会话信息(如验证码的正确答案)保存在服务器上,同时将标记session的session_id传递给客户端浏览器
2. session_id会以cookie的方式保存到浏览器的缓存中,当浏览器请求的url与该cookie的domain和path匹配,就会携带该cookie,服务器根据cookie中的session_id,就能取得客户端的数据状态(如之前存入的验证码)
3. 当浏览器关闭(或清理缓存),该cookie就会清掉。但服务器保存的session则在达到过期时间时,才会释放
import urllib2
import cookielib
base_url="http://xxx"
login_url="http://xxx"
captcha_url="http://xxx"
函数:__init__()
# 创建一个OpenerDirector的实例,传入一个CookieJar的Handler,用于自动处理cookie
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(
urllib2.HTTPCookieProcessor(cookie))
# 向opener中addheaders,之后用这个opener提交的request都会自动加入这些首部字段
opener.addheaders = [
('User-Agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.100 Safari/537.36'),
('Connection', 'keep-alive')]
# 将上面的opener安装为全局默认浏览器
urllib2.install_opener(opener)
函数:get_captcha()
urllib2.Request(captcha_url) # 构造访问captcha_url的request
# 提交该请求,获取验证码
response = opener.open(urllib2.Request(captcha_url))
for item in cookie: # 可以查看访问后的cookie信息
print item.name, item.value
# 读取响应正文的出二进制流数据:验证码图片
data_binary_flow = response.read()
# 保存验证码图片
# response的Content-Type:image/Gif,所以验证码图片保存为.gif格式
print response.info() # 可以读取响应的信息,如headers
captcha_image = open('captcha.gif', 'wb')
captcha_image.write(data_binary_flow)
# 刷新缓冲区,把数据写到磁盘上,确保程序运行到此处图片已经更新
captcha_image.flush()
captcha_image.close()
函数:login()
# 1.获取__VIEWSTATE的值
# GET拉取登录页面,post登录时有一个字段需要在这个页面获取
response = opener.open(login_url)
# 在HTML页面中正则匹配出__VIEWSTATE参数的值
login_page = response.read()
# (.*?) 非贪婪匹配除"\n"外的多个字符,()为分组,只获取分组内的部分
pattern_viewstate = re.compile(r'"__VIEWSTATE" value="(.*?)"')
param_viewstate = re.findall(pattern_viewstate, login_page)[0]
# 2.post:登录系统,获取首页页面
post_param = {
'__VIEWSTATE': param_viewstate,
'txtUserName': self.stu_id,
'TextBox2': self.password,
'txtSecretCode': verify_code,
'RadioButtonList1':'',
'Button1': '',
'lbLanguage': '',
'hidPdrs': '',
'hidsc': ''}
# Request带上参数时,就会以post方式向url提交请求
request = urllib2.Request(login_url,urllib.urlencode(post_param))
# request.add_header('Referer',login_url) # 不加也可以
response = self.opener.open(request)
home_page = response.read() # 获取首页
# 为了正确的正则匹配,统一全部用unicode编码
home_page = home_page.decode('gb2312')
# 正则匹配找出课表页面的path
course_url_pattern = re.compile(ur'专业推荐课表查询学生个人课表' )
course_url = re.findall(course_url_pattern, home_page)[0]
if len(course_url) == 0: # 若登录失败,匹配无内容
return -1
course_url = base_url + u'/' + course_url # 课程表页面url
# unicode有些字符encode失败,所以先转成utf-8
request = urllib2.Request(course_url.encode('utf-8'))
# 必须加Referer头字段,否则无法正常访问
request.add_header('Referer',base_url+'/xs_main.aspx?xh='+self.stu_id)
response = opener.open(request)
# 第二个参数,表示对解码错误的处理方式,默认是'strict':raise a UnicodeError
# 课程有关的字符解码不会出错,所以选择ignore忽略其他解码错误
course_page = response.read().decode('gb2312', 'ignore')
python正则表达式对照表
Python爬虫之正则 & BeautifulSoup4解析HTML
参考:
HTTP头子段意义
python-urllib2官网文档
Python标准库urllib2的使用细节
如果对你有所帮助,就请点个赞吧 (^-^)