赞
踩
Python的爬虫框架主要可以分为以下五个部分:
爬虫调度器:用于各个模块之间的通信,可以理解为爬虫的入口与核心(main函数),爬虫的执行策略在此模块进行定义;
URL管理器:负责URL的管理,包括带爬取和已爬取的URL、已经提供相应的接口函数(类似增删改查的函数)
网页下载器:负责通过URL将网页进行下载,主要是进行相应的伪装处理模拟浏览器访问、下载网页
网页解析器:负责网页信息的解析,这里是解析方式视具体需求来确定
信息采集器:负责将解析后的信息进行存储、显示等处理
代码示例是爬取CSDN博主下的所有文章为例,文章仅作为笔记使用,理论知识rarely
一、网页解析器简介
解析器的工作就是按需求对网页进行解析,并将解析信息进行处理。
解析器可以选择的工具有很多种,在这个博客里使用的时BeautifulSoup + 正则表达式进行信息的提取。BeautifulSoup使用起来比较方便(其他的目前还不会,没接触) ,因为不熟,所以不做技术说明,近将经过尝试的结果呈现。
二、网页解析器示例:(爬取CSDN博主下的所有文章)
- # author : sunzd
- # date : 2019/3/22
- # position: chengdu
-
- from bs4 import BeautifulSoup
- from urllib import error
- import re
-
-
- class HtmlParser(object):
- def __init__(self):
- # self.articles = {}
- # self.articles_url = set()
- # self.articles_title = set()
- # self.articles_date = set()
- self.url_page = None
-
- '''
- print(link.parent.span) :
- <span class="article-type type-1">原</span>
- print(link.parent.span.text) :
- 节点span的内容:原
- print(link.parent.get('href')) :
- https://blog.csdn.net/s2603898260/article/details/85067018
- https://blog.csdn.net/s2603898260/article/details/85020006
- '''
- '''
- get_article_urls最后的结果只获取了文章的URL,其中大部分代码为调试记录,没删除
- '''
- def get_article_urls(self, page_url, soup):
- # 1. 根据文章类型来确定文章信息
- # links = soup.find_all('span', class_=re.compile(r"article-type type-[0-9]"))
- # article_titles = soup.find_all('div', attrs={'class':"article-item-box csdn-tracking-statistics",'data-articleid':"\d+"})
- # article_info = soup.find_all('div', class_="info-box d-flex align-content-center")
-
- '''
- <div>
- --< h4 >
- --< p >
- --< div >
- links = soup.find_all('div', attrs={'class':"article-item-box csdn-tracking-statistics"})
- # 获取文章标题信息
- print(links[0].h4) # ok
- # 获取文章简介信息
- print(links[0].div.p)
- # 获取文章发表时间、阅读量信息
- for child in links[0].div.children:
- if len(child) != 3: # 去除空的子标签
- continue
- print(child.span.text) # print(child.span)
- if len(links) > 0:
- for link in links:
- print(link.next_sibling.next_sibling.next_sibling.next_sibling)
- print(link)
- print("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-")
- '''
- articles_url = set()
- links = soup.find_all('div', attrs={'class':"article-item-box csdn-tracking-statistics"})
- if len(links) > 0:
- for link in links:
- try:
- if link.attrs['style']: # 去除第一个不属于该博主的链接
- continue
- except KeyError as e:
- articles_url.add(link.h4.a.get('href')) # ******文章链接******
- # print(link.h4.a.attrs['href']) #get attrs在此等价
- # tmp = link.h4.a.text
- # tmp = tmp.replace("原", "")
- # tmp = tmp.replace("转", "")
- # tmp = tmp.replace("\n", "")
- # self.articles_title.add(tmp.replace(" ", "")) # 文章标题
- # for child in link.div.children:
- # if len(child) != 3: # 去除空的子标签
- # continue
- # # print(child.span.text) # print(child.span)
- # self.article_date.add()
-
- # self.articles = dict(zip(self.articles_url, self.articles_title)) 将两个列表合并为字典
- # tmp = self.articles_url.pop()
- # print(self.articles_url)
- # print("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-")
-
- return articles_url
-
- '''
- 第一页:
- <li data-page="1" class="ui-pager focus">1</li>
- <li class="js-page-next js-page-action ui-pager">下一页</li>
- <li class="js-page-last js-page-action ui-pager"></li>
- 第二页:
- <li data-page="2" class="ui-pager focus">2</li>
- <li class="js-page-next js-page-action ui-pager ui-pager-disabled">下一页</li>
- <li class="js-page-last js-page-action ui-pager ui-pager-disabled"></li>
- '''
- def get_page_url(self, page_url, soup):
- if page_url is None or soup is None:
- return None
-
- # https://blog.csdn.net/s2603898260/article/list/1?
- # 获取当前页
- cur_page = soup.find('li', attrs={'class':"ui-pager focus"}) #attrs={'class':"ui-pager focus"}
- print(cur_page)
- # 判断是否有下一页
- # links = soup.find('li', class_=re.compile(r"js-page-last.+ui-pager-disabled"))
- links = soup.find('li', class_="js-page-next js-page-action ui-pager ui-pager-disabled")
-
- if links is None or len(links) == 0:
- self.url_page = None
- return self.url_page
- # 寻找下一页
- # TODO:
-
- return self.url_page
-
- def parser(self, page_url, html):
- if html is None or page_url is None:
- print("html or page_url is None")
- return None
- soup = BeautifulSoup(html, 'html.parser', from_encoding='utf-8')
- articles = self.get_article_urls(page_url, soup)
- #new_page = self.get_page_url(page_url, soup)
-
- return articles
三、上述代码用到的知识点:
1. BeautifulSoup Note:
soup = BeautifulSoup(html, 'html.parser', from_encoding='utf-8') # 将html转换为标记树的形式soup
使用find_all()寻找符合属性的所有节点信息:
article_titles = soup.find_all('div', attrs={'class':"article-item-box csdn-tracking-statistics",'data-articleid':"\d+"})
可以使用find()寻找符合属性的第一个节点信息,一般这个节点为大节点.(以下为假设)
- 如博客的正文节点<div>,可以先通过find找到<div>, 然后在一次遍历其他的节点、寻找所有符合要求的图片等
- # find('div',attrs={}).find_all('p',attrs={})
- # <div>
- # ----< h4 >
- # ----< p >
- # ----< div >
- # ---------< p >
- # ---------< p >
- # ---------< p >
-
- # 获取文章标题信息
- print(links[0].h4) # ok
- # 获取文章简介信息
- print(links[0].div.p)
- # 获取文章发表时间、阅读量信息
- for child in links[0].div.children:
- if len(child) != 3: # 去除空的子标签
- continue
- # print(child.span.text) #打印节点文本信息
- # print(child.span) #打印整个节点信息
打印节点属性信息:
# print(link.h4.a.get('href')) # 文章链接 # print(link.h4.a.attrs['href']) # 文章链接 两个等价
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。