怎样用Python 写一个爬虫框架( 三 )

实际运行一下,会输出请求状态200,就这样简单封装一下,我们已经有了自己的请求类Request,接下来只需要再完善一下重试机制以及将返回的属性封装一下就基本完成了:
# 重试函数async def _retry(self): if self.retry_times \u0026gt; 0: retry_times = self.request_config.get(\u0026#39;RETRIES\u0026#39;, 3) - self.retry_times + 1 self.retry_times -= 1 retry_func = self.request_config.get(\u0026#39;RETRY_FUNC\u0026#39;) if retry_func and iscoroutinefunction(retry_func): request_ins = await retry_func(weakref.proxy(self)) if isinstance(request_ins, Request): return await request_ins.fetch() return await self.fetch()最终代码见ruia/request.py即可,接下来就可以利用Request来实际请求一个目标网页,如下:
怎样用Python 写一个爬虫框架

这段代码请求了目标网页https://docs.python-ruia.org/并返回了Response对象,其中Response提供属性介绍如下:
怎样用Python 写一个爬虫框架

Field \u0026amp; Item 实现了对目标网页的请求,接下来就是对目标网页进行字段提取,我觉得ORM的思想很适合用在这里,我们只需要定义一个Item类,类里面每个属性都可以用Field类来定义,然后只需要传入url或者html,执行过后Item类里面 定义的属性会自动被提取出来变成目标字段值
可能说起来比较拗口,下面直接演示一下可能你就明白这样写的好,假设你的需求是获取HackerNews网页的titleurl,可以这样实现:
import asynciofrom ruia import AttrField, TextField, Itemclass HackerNewsItem(Item): target_item = TextField(css_select=\u0026#39;tr.athing\u0026#39;) title = TextField(css_select=\u0026#39;a.storylink\u0026#39;) url = AttrField(css_select=\u0026#39;a.storylink\u0026#39;, attr=\u0026#39;href\u0026#39;)async def main(): async for item in HackerNewsItem.get_items(url="https://news.ycombinator.com/"): print(item.title, item.url)if __name__ == \u0026#39;__main__\u0026#39;: items = asyncio.run(main())怎样用Python 写一个爬虫框架


从输出结果可以看到,titleurl属性已经被赋与实际的目标值,这样写起来是不是很简洁清晰也很明了呢?
来看看怎么实现,Field类的目的是提供多种方式让开发者提取网页字段,比如:
XPathCSS SelectorRE所以我们只需要根据需求,定义父类然后再利用不同的提取方式实现子类即可,代码如下:
class BaseField(object): """ BaseField class """ def __init__(self, default: str = \u0026#39;\u0026#39;, many: bool = False): """ Init BaseField class url: http://lxml.de/index.html :param default: default value :param many: if there are many fields in one page """ self.default = default self.many = many def extract(self, *args, **kwargs): raise NotImplementedError(\u0026#39;extract is not implemented.\u0026#39;)class _LxmlElementField(BaseField): passclass AttrField(_LxmlElementField): """ This field is used to get attribute. """ passclass HtmlField(_LxmlElementField): """ This field is used to get raw html data. """ passclass TextField(_LxmlElementField): """ This field is used to get text. """ passclass RegexField(BaseField): """ This field is used to get raw html code by regular expression. RegexField uses standard library `re` inner, that is to say it has a better performance than _LxmlElementField. """ pass


推荐阅读