HTTP请求与响应组成与正则解析总结

引言

本篇依然是一个记录学习过程以及打卡的一篇博文。

get和post请求

import urllib.request

def send_request():
    # 发送指定的url地址请求,返回一个类文件的响应对象
    response = urllib.request.urlopen("http://www.baidu.com/")
    # 读取响应中内容,获取网页原始编码字符串
    html = response.read()
    return html

if __name__ == '__main__':
    html = send_request()
    print(html)

返回的是以byte形式返回的源码。

如果断开网络后,会出现如下错误:

urllib.error.URLError: <urlopen error [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。>

然后以下问题均出自《python面试宝典》一书,我只是手敲顺便思考了一遍:

问题一:常见的反爬虫和应对方法?

反爬虫简单的说指的是: 网站根据某些因素断定该请求是一个爬虫程序发出的请求,然后对该请求采取一定的制裁措施。
因此反爬虫应该从两方面来探讨:

  1. 网站如何断定该请求是一个爬虫:请求头、请求频率、IP地址、cookie等(持续更新请求头、cookie、用户cookie池、代理IP池、设置一定的延时)
  2. 网站如何制裁这个它认为是爬虫的请求(假数据、空数据、不返回响应、验证码、4xx状态码等)

通过Headers反爬虫:
  从用户请求的Headers反爬虫是最常见的反爬虫策略。很多网站都会对Headers的User-Agent进行检测,还有一部分网站会对Referer进行检测(一些资源网站的防盗链就是检测Referer)。如果遇到了这类反爬虫机制,可以直接在爬虫中添加Headers,将浏览器的User-Agent复制到爬虫的Headers中;或者将Referer值修改为目标网站域名。对于检测Headers的反爬虫,在爬虫中修改或者添加Headers就能很好的绕过。

基于用户行为反爬虫:
  还有一部分网站是通过检测用户行为,例如同一IP短时间内多次访问同一页面,或者同一账户短时间内多次进行相关操作。
  大多数网站都是前一种情况,对于这种情况,使用IP代理就可以解决。可以专门写一个爬虫,爬取网上公开的代理IP,检测后全部保存起来,这样的代理IP爬虫经常会用到,最好自己准备一个。有了大量代理ip后可以每请求几次更换一个ip,这在requests或者urllib2中很容易做到,这样就能很容易的绕过第一种反爬虫。
  对于第二种情况,可以在每次请求后随机间隔几秒在进行下一次请求,有些有逻辑漏洞的网站,可以通过请求几次,退出登录,重新登录,继续请求来绕过同一账号短时间内不能多次进行相同请求的限制。

动态页面的反爬虫:
  未完待续。



正则表达式

昨天一天有事,晚上和大学同学吃了顿火锅,表示还行。好了,废话不多说,进入正题。

HTTP的请求解析

在上一节我们提到了get请求和post请求,但我并没有解释关于其中的方式与特点,主要是当时看别人都打卡了,然后自己也不想看,就过了,今天比较难得的一个周六,那么就让我们来复习一下吧。内容参考HTTP请求行、请求头、请求体详解

客户端发送一个HTTP请求到服务器的请求消息,包括以下格式:请求行请求头部空行请求数据。这四个共同构成了HTTP的请求消息结构,然后这里我上面参考的网站里有一张汇总的图,这里我就不再引述了,主要是要知道各种基本的结构解释。那么我们来看如下图:

在这里插入图片描述
上述是基于post请求产生的请求报文,get方式的布局基本和其一致,它们是两种最常见的HTTP方法,除了它们还有DELETE、HEAD、OPTIONS、PUT、TRACE、CONNECT方式,那么下面通过表格我们可以来认识各自的含义:

序号方法描述
1GET请求指定的页面信息,并返回实体主体
2POST向指定资源请求数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求体重,POST请求可能会导致新的资源的简历或已有资源的修改。
3HEAD类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
4PUT从客户端向服务器传送的数据取代指定的文档的内容
5DELETE请求服务器删除指定的页面
6CONNECTHTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
7OPTIONS允许客户端查看服务器的性能
8TRACE回显服务器收到的请求,主要用于测试或诊断

HTTP中GET和POST请求的异同:

  1. GET是从服务器上获取指定页面信息,POST是向服务器提交数据并获取页面信息。
  2. GET请求参数都显示在URL上,服务器根该请求所包含URL中的QueryString参数来产生响应内容。“GET”请求的参数是URL的一部分。
  3. POST请求参数在请求体Formdata中,消息长度没有限制而且以隐式的方式进行发送,通常用来向HTTP服务器提交量比较大的数据(比如请求中包含许多参数或者文件上传操作等)。“POST”请求的参数不再URL中,而在请求体中。

Http 1.1支持的请求报头: (参考自文章 HTTP 1.1的常用请求报头)

  1. Accept(传输文件类型): 指定浏览器或其他客户端程序所能处理的MIME类型(IE5和6在重新载入页面时,发送的Accept报头不正确,但在最初的请求中是正确的)。

    举例:
    Accept: /:表示什么都可以接收。

    Accept:image/gif:表明客户端希望接受GIF图像格式的资源;

    Accept:text/html:表明客户端希望接受html文本。

    Accept: text/html, application/xhtml+xml;q=0.9, image/*;q=0.8:表示浏览器支持的 MIME 类型分别是 html文本、xhtml和xml文档、所有的图像格式资源。

  2. Accept-Charset(字符编码): 标明浏览器可以使用的字符集(如ISO-8859-1).

  3. Accept-Encoding(文件编解码格式): 详细列出客户端能处理的编码类型(gzip,compress是两种常见的值),一般来讲花在解码上的时间要远远小于传输的开销。

  4. Accept-Language(语言种类): 在servlet能够以多种语言生产结果时,列出客户程序首选的语言。这个报头的值应该是标准语言代码的一种,比如en, en-us, da等。

  5. Authorization(认证): 在访问密码保护的WEB页面时,客户用这个报头来识别自己的身份。(Https)

  6. Connection(连接类型): 标明客户是否能够处理持续性HTTP连接。持续性(Keep-Alive)是默认的选项。

  7. Content-Length(POST数据大小): 只适用于POST请求,用来给定POST数据的大小,以字节为单位。request.getContentlength()方法得到这个报头。

  8. Content-Type(POST数据类型):
    Content-Type:POST请求里用来表示的内容类型。
    举例:Content-Type = Text/XML; charset=gb2312:
    指明该请求的消息体中包含的是纯文本的XML类型的数据,字符编码采用“gb2312”。

  9. Cookie(“曲奇”,产生记录): 这个报头向服务器返回cookie,这些cookie是之前服务器发送给浏览器的。使用request.getCookies读取这个报头。

  10. Host(主机和端口号): 在HTTP1.1中,浏览器和其他客户端程序需要制定这个报头,它标明原始URL中给出的主机名和端口号。

  11. If-Modified-Since/If-Unmodified-Since: 这个报头标明,仅当页面在指定日期之后发生更改的情况下,客户程序才希望获取该页面。否则反之为Unmodified,表示未修改或不可改变,即文档比指定的日期要旧才能继续操作。

  12. Referer(页面跳转来源): 标明引用Web页面的URL。例如,WEB1单击指向WEB2的链接,在浏览器请求WEB2页面是会把Referer指定为WEB1的URL。
    referer还有一个功能就是做防盗链,即我们在查询相应的一些信息如文件、图片等,需要对应的referer,比如说拉钩网的招聘信息,它会判断是否是从主页进来的,否则会拒绝请求。

  13. Use-Agent(浏览器名称): 标识生产请求的浏览器或其他客户端程序,根据这个报头,可以针对不同类型的浏览器返回不同的内容。

  14. Upgrade-Insecure-Requests(升级为HTTPS请求): Upgrade-Insecure-Requests:升级不安全的请求,意思是会在加载 http 资源时自动替换成 https 请求,让浏览器不再显示https页面中的http请求警报。


HTTP响应状态码:
HTTP常见的响应报头和请求报头差不多,而在爬虫中,其实作用不是太大,而比较重要的就是HTTP的错误状态码了,有时候我们的错误就是根据状态码先确定一个大致的范围,才能节省更多的时间改正BUG。这里我做了一个记录,没有再做整理了,比较全面的一个HTTP状态码见Wiki:

https://zh.wikipedia.org/wiki/HTTP状态码

然后收集了几张比较好的图片,在这里分享一下:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

运用正则爬取豆瓣信息

关于正则表达式,这里我就不再多说了,它的底层研究了半小时,发现没看懂然后就略过吧。。几个月前复习的时候画的思维导图如下:

在这里插入图片描述

那么我们可以直接来看问题,需要我们用正则表达式爬取豆瓣电影 Top 250里的内容包括名次、影片名称、国家、导演等字段,首先我们需要去分析网页,那么就进入豆瓣的官网,然后找到排行版里按F12进入开发者模式,然后再选定关于显示导演电影等信息的标签,然后首先得到了该网站是动态的:

http://movie.douban.com/top250?start=(page_num)&filter=

然后找到了相关的标签为:
在这里插入图片描述

这里如果单单是爬取前250条,应该还不用考虑反爬,参考代码为利用Requests库和正则表达式爬取豆瓣影评Top250

#!/usr/bin/env python 
# -*- coding:utf-8 -*-
import requests
import re
import json
from requests.exceptions import RequestException
#得到网页源代码
def get_one_page(url):
    try:
        res=requests.get(url)
        if res.status_code==200:
            return  res.text
        return  None
    except RequestException:
        return  None
#对源代码进行解析将要获取的数据存储到dict当中去然后写入本地文件
def parse_one_html(html):
    regex='<em class="">(\d+)</em>.*?<span class="title">(.*?)</span>.*?<p class="">(.*?)</p>.*?<span class="rating_num" property="v:average">(.*?)</span>.*?<span>(.*?)</span>.*?<span class="inq">(.*?)</span>'
    pattern=re.compile(regex,re.S)
    items=re.findall(pattern,html)
    #对得到的list列表进行处理,将每条记录变成一个dict
    for item in items:
        content=""
        for every_list in item[2].split():
            content=content+"".join(every_list)
        content=re.sub(' ',' ',content)
        content=re.sub('<br>', '', content)
        #将获取到的信息存储到dict字典当中
        dict={
            "number":item[0],
            "name":item[1],
            "describe":content,
            "star":item[3],
            "evaluate":item[4],
            "title":item[5]
 
        }
        #将得到的dict写入本地文件当中去
        with open('result.txt','a',encoding='utf-8') as f:
            f.write(json.dumps(dict,ensure_ascii=False)+'\n')
def main(start):
    url='https://movie.douban.com/top250'
    if start!=0:
        url='https://movie.douban.com/top250?start='+str(start)+'&filter='
    html=get_one_page(url)
    parse_one_html(html)
if __name__=='__main__':
    for i in range(10):
        main(i*25)

在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值