c爬虫抓取网页数据( 爬取*敏*感*词*图片的大体实现过程的应用框架使用方法介绍)

优采云 发布时间: 2021-10-21 05:30

  c爬虫抓取网页数据(

爬取*敏*感*词*图片的大体实现过程的应用框架使用方法介绍)

  

  scrapy是为爬取网站数据和提取结构化数据而编写的应用框架。更多关于框架的使用,请参考官方文档。本文文章展示了爬取*敏*感*词*图片的一般实现过程。

  Scrapy环境配置

  首先是scrapy的安装。博主使用Mac系统,直接运行命令行:

  pip install Scrapy

  对于html节点信息的提取,使用了Beautiful Soup库。大概的用法可以看上一篇文章,可以直接通过命令安装:

  pip install beautifulsoup4

  目标网页的 Beautiful Soup 对象的初始化需要 html5lib 解释器。安装命令:

  pip install html5lib

  安装完成后,直接在命令行运行命令:

  scrapy

  可以看到如下输出,证明scrapy安装完成。

  Scrapy 1.2.1 - no active projectUsage: scrapy [options] [args]Available commands: bench Run quick benchmark test commands fetch Fetch a URL using the Scrapy downloader genspider Generate new spider using pre-defined templates runspider Run a self-contained spider (without creating a project) settings Get settings values  ...

  项目创建通过命令行在当前路径下创建一个名为Comics的项目

  scrapy startproject Comics

  创建完成后,当前目录下会出现对应的工程文件夹,可以看到生成的Comics文件结构为:

  |____Comics| |______init__.py| |______pycache__| |____items.py| |____pipelines.py| |____settings.py| |____spiders| | |______init__.py| | |______pycache__|____scrapy.cfg

  附言。打印当前文件结构的命令是:

  find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'

  每个文件对应的具体功能可以在官方文档中找到。这个实现没有涉及很多这些文件,所以没有列出下表。1、创建蜘蛛类创建一个类来实现具体的爬取功能。我们所有的处理和实现都会在这个类中进行。它必须是scrapy.Spider 的子类。在 Comics/spiders 文件路径中创建一个 Comics.py 文件。comics.py 的具体实现:

  #coding:utf-8import scrapyclass Comics(scrapy.Spider): name = "comics" def start_requests(self): urls = ['http://www.xeall.com/shenshi'] for url in urls: yield scrapy.Request(url=url, callback=self.parse) def parse(self, response): self.log(response.body);

  自定义类是scrapy.Spider的子类,其中name属性是爬虫的唯一标识,作为scrapy爬取命令的参数。其他方法的属性将在后面解释。2、 运行创建的自定义类后,切换到Comics路径,运行命令,启动爬虫任务,开始爬取网页。

  scrapy crawl comics

  打印的结果是爬虫运行过程中的信息和目标爬取网页的html源代码。

  2016-11-26 22:04:35 [scrapy] INFO: Scrapy 1.2.1 started (bot: Comics)2016-11-26 22:04:35 [scrapy] INFO: Overridden settings: {'ROBOTSTXT_OBEY': True, 'BOT_NAME': 'Comics', 'NEWSPIDER_MODULE': 'Comics.spiders', 'SPIDER_MODULES': ['Comics.spiders']}2016-11-26 22:04:35 [scrapy] INFO: Enabled extensions:['scrapy.extensions.corestats.CoreStats', 'scrapy.extensions.telnet.TelnetConsole', 'scrapy.extensions.logstats.LogStats'] ...

  至此,一个基本的爬虫就创建好了。下面是具体的实现过程。爬取*敏*感*词*图片1、起始地址爬虫的起始地址为:

  http://www.xeall.com/shenshi

  我们主要关注页面中间的*敏*感*词*列表,列表底部有显示页数的控件。如下所示

  

  爬虫的主要任务是爬取列表中每个*敏*感*词*的图片。爬完当前页面后,进入*敏*感*词*列表的下一页继续爬取*敏*感*词*,继续循环,直到所有的*敏*感*词*都被爬取完毕。我们将起始地址的 url 放在 start_requests 函数的 urls 数组中。其中,start_requests 是重载父类的方法。该方法会在爬虫任务启动时执行。start_requests方法的主要执行在这行代码:请求指定的url,请求完成后调用对应的回调函数self.parse

  scrapy.Request(url=url, callback=self.parse)

  其实还有另外一种方式可以实现前面的代码:

  #coding:utf-8import scrapyclass Comics(scrapy.Spider): name = "comics" start_urls = ['http://www.xeall.com/shenshi'] def parse(self, response): self.log(response.body);

  start_urls 是框架中提供的一个属性。它是一个收录目标网页 URL 的数组。设置 start_urls 的值后,不需要重载 start_requests 方法。爬虫也会依次爬取start_urls中的地址,并在请求完成后自动调用parse。作为回调方法。不过为了方便过程中其他回调函数的调整,demo中还是沿用了之前的实现方式。2、 爬取*敏*感*词*的url 从最初的网页开始,我们首先要爬取每个*敏*感*词*的url。当前页*敏*感*词*列表的起始页为*敏*感*词*列表的第一页。我们需要从当前页面中提取需要的信息并实现回调解析方法。

  from bs4 import BeautifulSoup

  请求返回的html源码用于初始化BeautifulSoup。

  def parse(self, response): content = response.body; soup = BeautifulSoup(content, "html5lib")

  初始化时指定了html5lib解释器,未安装会报错。如果在初始化 BeautifulSoup 时没有提供指定的解释器,它会自动使用它认为匹配的最佳解释器。有一个陷阱。对于目标网页的源代码,默认的最佳解释器是lxml,解析结果会出现Problems,无法进行后续的数据提取。所以当你发现有时提取结果有问题的时候,打印汤看是否正确。查看html源码,可以看到页面显示*敏*感*词*列表的部分是ul标签,类名是listcon,对应的标签可以通过listcon类唯一确认

  

  提取收录*敏*感*词*列表的标签

  listcon_tag = soup.find('ul', class_='listcon')

  上面的find方法就是查找class为listcon的ul标签,返回对应标签的所有内容。在列表标签​​中查找所有带有 href 属性的标签。这些a标签是每个*敏*感*词*对应的信息。

  com_a_list = listcon_tag.find_all('a', attrs={'href': True})

  然后将每个*敏*感*词*的href属性组合成一个完整的可访问的URL地址,并保存在一个数组中。

  comics_url_list = []base = 'http://www.xeall.com' for tag_a in com_a_list: url = base + tag_a['href'] comics_url_list.append(url)

  此时,comics_url_list 数组收录当前页面上每个*敏*感*词*的 url。3、下一页列表,查看列表下方的选择页面控件,我们可以通过这个地方获取下一页的url。

  

  获取所选页面标签中收录 href 属性的所有标签

  page_tag = soup.find('ul', class_='pagelist')page_a_list = page_tag.find_all('a', attrs={'href': True})

  这部分源代码如下图所示。可以看到,在所有a标签中,倒数第一个代表最后一页的网址,倒数第二个代表下一页的网址。因此,我们可以取page_a_list数组中倒数第二个元素来获取下一页的url。

  

  但是这里需要注意的是,如果当前页面是最后一页,则不需要去取下一页。那么如何判断当前页面是否为最后一页呢?可以通过select控件来判断。从源码可以判断当前页面对应的option标签会有selected属性。下图显示当前页面为第一页

  

  下图显示当前页面为最后一页

  

  当前页码与最后页码比较,如果相同,则表示当前页为最后一页。

  select_tag = soup.find('select', attrs={'name': 'sldd'})option_list = select_tag.find_all('option')last_option = option_list[-1]current_option = select_tag.find('option' ,attrs={'selected': True})is_last = (last_option.string == current_option.string)

  当前页面不是最后一页,那么在下一页继续做同样的处理,请求还是通过回调parse方法处理

  if not is_last: next_page = 'http://www.xeall.com/shenshi/' + page_a_list[-2]['href'] if next_page is not None: print('\n------ parse next page --------') print(next_page) yield scrapy.Request(next_page, callback=self.parse)

  以相同的方式依次处理每一页,直到处理完所有页。4、 爬取*敏*感*词*图片,在parse方法中提取当前页面的所有*敏*感*词*URL时,就可以开始处理每一个*敏*感*词*了。在得到的comics_url_list数组下面添加如下代码:

  for url in comics_url_list: yield scrapy.Request(url=url, callback=self.comics_parse)

  请求每个*敏*感*词*的url,回调处理方法是ics_parse,comics_parse方法用于处理每个*敏*感*词*。下面是具体的实现。5、当前页面图片的首相根据请求返回的源码构造一个BeautifulSoup,与上一个基本一致

  def comics_parse(self, response): content = response.body; soup = BeautifulSoup(content, "html5lib")

  提取select页面控件标签,页面显示及源码如下

  

  

  提取类为pagelist的ul标签

  page_list_tag = soup.find('ul', class_='pagelist')

  查看源码,可以看到当前页面的li标签的class属性thisclass,从而得到当前页面的编号

  current_li = page_list_tag.find('li', class_='thisclass')page_num = current_li.a.string

  当前页面图片的标签及对应的源码

  

  

  获取当前页面图片的url和*敏*感*词*的标题。*敏*感*词*标题后,用作存放相应*敏*感*词*的文件夹名称。

  li_tag = soup.find('li', id='imgshow')img_tag = li_tag.find('img')img_url = img_tag['src']title = img_tag['alt']

  6、保存到本地 提取图片url后,可以通过url请求图片,保存到本地

  self.save_img(page_num, title, img_url)

  专门定义了一个方法 save_img 来保存图片。具体完整的实现如下

  # 先导入库import osimport urllibimport zlibdef save_img(self, img_mun, title, img_url): # 将图片保存到本地 self.log('saving pic: ' + img_url) # 保存*敏*感*词*的文件夹 document = '/Users/moshuqi/Desktop/cartoon' # 每部*敏*感*词*的文件名以标题命名 comics_path = document + '/' + title exists = os.path.exists(comics_path) if not exists: self.log('create document: ' + title) os.makedirs(comics_path) # 每张图片以页数命名 pic_name = comics_path + '/' + img_mun + '.jpg' # 检查图片是否已经下载到本地,若存在则不再重新下载 exists = os.path.exists(pic_name) if exists: self.log('pic exists: ' + pic_name) return try: user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' headers = { 'User-Agent' : user_agent } req = urllib.request.Request(img_url, headers=headers) response = urllib.request.urlopen(req, timeout=30) # 请求返回到的数据 data = response.read() # 若返回数据为压缩数据需要先进行解压 if response.info().get('Content-Encoding') == 'gzip': data = zlib.decompress(data, 16 + zlib.MAX_WBITS) # 图片保存到本地 fp = open(pic_name, "wb") fp.write(data) fp.close self.log('save image finished:' + pic_name) except Exception as e: self.log('save image error.') self.log(e)

  该函数主要使用3个参数,当前图片的页数,*敏*感*词*名称,图片的url。图片将保存在以*敏*感*词*命名的文件夹中。如果没有对应的文件夹,就创建一个。一般拿到第一张图片的时候就需要创建一个文件夹。文档是本地指定的文件夹,可以自定义。每张图片都以 pages.jpg 格式命名。如果本地已经存在同名图片,则不会重新下载。一般用于判断任务何时重复,避免重复请求已有图片。请求返回的图片数据是经过压缩的,可以通过().get('Content-Encoding')的类型来判断。压缩后的图片必须通过zlib.decompress解压后保存到本地,否则图片无法打开。大体实现思路如上,代码也附上注释。7、下一页图片类似*敏*感*词*列表界面中的处理方法。在*敏*感*词*页面中,我们还需要不断的获取下一页的图片,继续遍历,直到最后一页。

  

  当next page标签的href属性为#时,就是*敏*感*词*的最后一页

  a_tag_list = page_list_tag.find_all('a')next_page = a_tag_list[-1]['href']if next_page == '#': self.log('parse comics:' + title + 'finished.')else: next_page = 'http://www.xeall.com/shenshi/' + next_page yield scrapy.Request(next_page, callback=self.comics_parse)

  如果当前页是最后一页,则*敏*感*词*遍历完成,否则继续下一页同理

  yield scrapy.Request(next_page, callback=self.comics_parse)

  8、 运行结果的大体实现基本完成。运行时可以看到控制台打印

  

  保存在本地文件夹中的图片

  

  在scrapy框架运行时,它使用了多个线程,可以看到多个*敏*感*词*同时在爬行。目标网站资源服务器感觉慢,经常出现请求超时。跑步时请耐心等待。最后,本文只介绍了scrapy框架非常基础的使用方法,以及各种非常详细的功能配置。如使用 FilesPipeline、ImagesPipeline 来保存下载的文件或图片。该框架本身带有一个用于提取网页信息的 XPath 类。这比 BeautifulSoup 更有效。也可以使用特殊的item类来保存爬取的数据结果并作为类返回。详情请参考官方网站。最后附上完整的Demo源码

  -结尾-

  原文链接:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线