python http简单例子

python http简单例子

python http框架主要有server和handler组成,server主要是用于建立网络模型,例如利用epoll监听socket;handler用于处理各个就绪的socket;先来看下python http简单的使用:

import sys
from http.server import HTTPServer,SimpleHTTPRequestHandler
 
ServerClass = HTTPServer
HandlerClass = SimpleHTTPRequestHandler
 
if__name__ =='__main__':
 port = int(sys.argv[2])
 server_address = (sys.argv[1],port)
 httpd = ServerClass(server_address,HandlerClass)
 
sa=httpd.socket.getsockname()
print("Serving HTTP on",sa[0],"port",sa[1],"...")
 
try:
 httpd.serve_forever()
 except KeyboardInterrupt:
print("\nKeyboard interrupt received, exiting.")
 httpd.server_close()
 sys.exit(0)

运行上述例子,可以得到如下:

python3 myhttp.py 127.0.0.1 9999

此时如果在当前文件夹新建一个index.html文件,就可以通过 访问了index.html页面了。

这个例子的server类用的是HTTPServer,handler类是SimpleHTTPRequestHandler,因此当HTTPServer监听到有request到来时,就把这个request丢给SimpleHTTPRequestHandler类求处理;ok,了解这些之后,我们开始分别分析下server和handler.

http之server

http模块的设计充分利用了面向对象的继承多态,因为之前有看了会tfs文件系统的代码,所以再看python http时,没那么大的压力;先给出server的继承关系

+------------------+
+------------+| tcpserver基类 |
| BaseServer +-------->| 开启事件循环监听 |
+-----+------+ | 处理客户端请求 |
 | +------------------+
 v +-----------------+
+------------+| httpserver基类 |
| TCPServer +-------->+设置监听socket |
+-----+------+ | 开启监听 |
 | +-----------------+
 v
+------------+
| HTTPServer | 
+------------+

继承关系如上图所示,其中BaseServer和TCPServer在文件socketserver.py,HTTPServer在http/server.py;我们先看下来BaseServer;

BaseServer

因为BaseServer是所有server的基类,因此BaseServer尽可能抽象出所有server的共性,例如开启事件监听循环,这就是每个server的共性,因此这也是BaseServer主要做的使;我们来看下BaseServer主要代码部分

defserve_forever(self, poll_interval=0.5):
 self.__is_shut_down.clear()
try:
with_ServerSelector()asselector:
 selector.register(self, selectors.EVENT_READ)
 
whilenotself.__shutdown_request:
 ready = selector.select(poll_interval)
ifready:
 self._handle_request_noblock()
 
 self.service_actions()
finally:
 self.__shutdown_request = False
 self.__is_shut_down.set()

代码中的selector其实就是封装了select,poll,epoll等的io多路复用,然后将服务自身监听的socket注册到io多路复用,开启事件监听,当有客户端连接时,此时会调用self._handle_request_noblock()来处理请求;接下来看下这个处理函数做了啥;

def_handle_request_noblock(self):
try:
 request, client_address = self.get_request()
exceptOSError:
return
ifself.verify_request(request, client_address):
try:
 self.process_request(request, client_address)
except:
 self.handle_error(request, client_address)
 self.shutdown_request(request)
else:
 self.shutdown_request(request)

_handle_request_noblock函数是一个内部函数,首先是接收客户端连接请求,底层其实是封装了系统调用accept函数,然后验证请求,最后调用process_request来处理请求;其中get_request是属于子类的方法,因为tcp和udp接收客户端请求是不一样的(tcp有连接,udp无连接)

我们接下来再看下process_request具体做了什么;

defprocess_request(self, request, client_address):
 self.finish_request(request, client_address)
 self.shutdown_request(request)
# -------------------------------------------------
deffinish_request(self, request, client_address):
 self.RequestHandlerClass(request, client_address, self)
 
defshutdown_request(self, request):
 self.close_request(request)

process_request函数先是调用了finish_request来处理一个连接,处理结束之后,调用shutdown_request函数来关闭这个连接;而finish_request函数内部实例化了一个handler类,并把客户端的socket和地址传了进去,说明,handler类在初始化结束的时候,就完成了请求处理,这个等后续分析handler时再细看;

以上就是BaseServer所做的事,这个BaseServer不能直接使用,因为有些函数还没实现,只是作为tcp/udp的抽象层;总结下:

先是调用serve_forever开启事件监听;
然后当有客户端请求到来时,将请求交给handler处理;
TCPServer

由上述BaseServer抽象出的功能,我们可以知道TCPServer或UDPServer应该完成的功能有,初始化监听套接字,并绑定监听,最后当有客户端请求时,接收这个客户端;我们来看下代码

BaseServer==>
def__init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
 self.server_address = server_address
 self.RequestHandlerClass = RequestHandlerClass
 self.__is_shut_down = threading.Event()
 self.__shutdown_request = False
#--------------------------------------------------------------------------------
TCPServer==>
def__init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
 BaseServer.__init__(self, server_address, RequestHandlerClass)
 self.socket = socket.socket(self.address_family,
 self.socket_type)
ifbind_and_activate:
try:
 self.server_bind()
 self.server_activate()
except:
 self.server_close()
raise

TCPServer初始化时先是调用基类BaseServer的初始化函数,初始化服务器地址,handler类等,然后初始化自身的监听套接字,最后调用server_bind绑定套接字,server_activate监听套接字

defserver_bind(self):
ifself.allow_reuse_address:
 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 self.socket.bind(self.server_address)
 self.server_address = self.socket.getsockname()
 
defserver_activate(self):
 self.socket.listen(self.request_queue_size)

TCPServer还实现了另一个函数,那就是接收客户端请求,

defget_request(self):
returnself.socket.accept()

之前如果有学过linux编程,那么看这些代码应该会觉得很熟悉,因为函数名和Linux提供的系统调用名一模一样,这里也不多说了;

TCPServer其实已经把基于tcp的服务器主体框架搭起来了,因此HTTPServer在继承TCPServer基础上,只是重载了server_bind函数,设置reuse_address等;

ok,这里分析下上述例子程序的开启过程;

httpd = ServerClass(server_address,HandlerClass)这行代码在初始化HTTPServer时,主要是调用基类TCPServer的初始化方法,初始化了监听的套接字,并绑定和监听;
httpd.serve_forever()这行代码调用的是基类BaseServer的serve_forever方法,开启监听循环,等待客户端的连接;
如果有看过redis或者一些后台组件的源码,对这种并发模型应该很熟悉;ok,分析了server之后,接下来看下handler是如何处理客户端请求的。

http之handler

handler类主要分析tcp层的handler和http应用层的handler,tcp层的handler是不能使用的,因为tcp层只负责传输字节,但是并不知对于接收到的字节要如何解析,如何处理等;因此应用层协议如该要使用TCP协议,必须继承TCP handler,然后实现handle函数即可;例如,http层的handler实现handle函数,解析http协议,处理业务请求以及结果返回给客户端;先来看下tcp层的handler

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单例子: 假设我们要从一个包含一些HTML元素的字符串中获取所有的链接和对应的文本内容。例如,我们有一个字符串变量`html_doc`,其内容如下: ```html <html> <head> <title>这是标题</title> </head> <body> <p>这是一个段落。</p> <a href="http://www.example.com">这是一个链接</a> <ul> <li><a href="http://www.example.com/link1">链接1</a></li> <li><a href="http://www.example.com/link2">链接2</a></li> <li><a href="http://www.example.com/link3">链接3</a></li> </ul> </body> </html> ``` 我们可以使用以下代码对其进行解析: ```python from bs4 import BeautifulSoup html_doc = """ <html> <head> <title>这是标题</title> </head> <body> <p>这是一个段落。</p> <a href="http://www.example.com">这是一个链接</a> <ul> <li><a href="http://www.example.com/link1">链接1</a></li> <li><a href="http://www.example.com/link2">链接2</a></li> <li><a href="http://www.example.com/link3">链接3</a></li> </ul> </body> </html> """ soup = BeautifulSoup(html_doc, 'html.parser') for link in soup.find_all('a'): href = link.get('href') text = link.get_text() print(href, text) ``` 以上代码中,我们首先导入了Beautifulsoup4库。然后,我们定义了一个包含HTML内容的字符串变量`html_doc`。接着,我们使用`BeautifulSoup`函数将`html_doc`解析成一个BeautifulSoup对象。最后,我们使用`find_all`方法查找所有的`a`标签,遍历所有的标签,获取链接和文本内容,并输出。 输出结果如下: ``` http://www.example.com 这是一个链接 http://www.example.com/link1 链接1 http://www.example.com/link2 链接2 http://www.example.com/link3 链接3 ``` 这个例子中,我们只是简单地将HTML内容解析成了一个BeautifulSoup对象,并遍历了所有的链接标签,获取链接和文本内容。如果需要对网页中的其他元素进行操作,可以使用BeautifulSoup提供的各种方法进行查找和操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值