怎样用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来实际请求一个目标网页,如下:
这段代码请求了目标网页https://docs.python-ruia.org/并返回了Response对象,其中Response提供属性介绍如下:
Field \u0026amp; Item 实现了对目标网页的请求,接下来就是对目标网页进行字段提取,我觉得ORM的思想很适合用在这里,我们只需要定义一个Item类,类里面每个属性都可以用Field类来定义,然后只需要传入url或者html,执行过后Item类里面 定义的属性会自动被提取出来变成目标字段值
可能说起来比较拗口,下面直接演示一下可能你就明白这样写的好,假设你的需求是获取HackerNews网页的title和url,可以这样实现: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())
从输出结果可以看到,title和url属性已经被赋与实际的目标值,这样写起来是不是很简洁清晰也很明了呢?
来看看怎么实现,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
推荐阅读
- 聪明人养花,这3种“花”怎样也要养一盆,每年能省不少医药费
- 同比■同比增长7.1%!2021年的第一个节你花了多少钱?
- “他是我第一个会说普通话的老师”:一对师生折射青海山村蝶变
- 有必要重新开个C店吗
- 互联网怎样解决“家政服务上门速度慢”的问题
- 怎样看待从1月8号起,QQ钱包开始提现收费
- 银行it人怎样转型
- 大学再有三个月就结束了,没学到知识,参加一个软件测试培训机构好吗
- 汽车|长安UNI-K又将开创一个新的"引力"纪元?
- 汽车|冬天怎样让车内温度快速升高?座椅加热的最佳使用方式二,外循环的作用总结
