之前看了一段有关爬虫的网课深有启发,于是自己也尝试着如如何过去爬虫百科“python”词条等相关页面的整个过程记录下来,方便后期其他人一起来学习。

抓取策略

确定目标:重要的是先确定需要抓取的网站具体的那些部分,下面实例是咦抓取百科python词条页面以及python有关页面的简介和标题。

分析目标:分析要抓取的url的格式,限定抓取范围。分析要抓取的数据的格式,本实例中就要分析标题和简介这两个数据所在的标签的格式。分析要抓取的页面编码的格式,在网页解析器部分,要指定网页编码,然后才能进行正确的解析。

编写代码:在网页解析器部分,要使用到分析目标得到的结果。

执行爬虫:进行数据抓取。

分析目标

1、url格式

进入百科python词条页面,页面中相关词条的链接比较统一,大都是/view/xxx.htm。

2、数据格式

标题位于类lemmaWgt-lemmaTitle-title下的h1子标签,简介位于类lemma-summary下。

3、编码格式

查看页面编码格式,为utf-8。

经过以上分析,得到结果如下:

代码编写

项目结构

在sublime下,新建文件夹baike-spider,作为项目根目录。

新建spider_main.py,作为爬虫总调度程序。

新建url_manger.py,作为url管理器。

新建html_downloader.py,作为html下载器。

新建html_parser.py,作为html解析器。

新建html_outputer.py,作为写出数据的工具。

具体代码示例:

spider_main.py

  1. # coding:utf-8
  2. import url_manager, html_downloader, html_parser, html_outputer
  3.  
  4. class SpiderMain(object):
  5. def __init__(self):
  6. self.urls = url_manager.UrlManager()
  7. self.downloader = html_downloader.HtmlDownloader()
  8. self.parser = html_parser.HtmlParser()
  9. self.outputer = html_outputer.HtmlOutputer()
  10.  
  11. def craw(self, root_url):
  12. count = 1
  13. self.urls.add_new_url(root_url)
  14. while self.urls.has_new_url():
  15. try:
  16. new_url = self.urls.get_new_url()
  17. print('craw %d : %s' % (count, new_url))
  18. html_cont = self.downloader.download(new_url)
  19. new_urls, new_data = self.parser.parse(new_url, html_cont)
  20. self.urls.add_new_urls(new_urls)
  21. self.outputer.collect_data(new_data)
  22.  
  23. if count == 10:
  24. break
  25.  
  26. count = count + 1
  27. except:
  28. print('craw failed')
  29.  
  30. self.outputer.output_html()
  31.  
  32. if __name__=='__main__':
  33. root_url = 'http://baike.baidu.com/view/21087.htm'
  34. obj_spider = SpiderMain()
  35. obj_spider.craw(root_url)

url_manger.py

  1. # coding:utf-8
  2. class UrlManager(object):
  3. def __init__(self):
  4. self.new_urls = set()
  5. self.old_urls = set()
  6.  
  7. def add_new_url(self, url):
  8. if url is None:
  9. return
  10. if url not in self.new_urls and url not in self.old_urls:
  11. self.new_urls.add(url)
  12.  
  13. def add_new_urls(self, urls):
  14. if urls is None or len(urls) == 0:
  15. return
  16. for url in urls:
  17. self.add_new_url(url)
  18.  
  19. def has_new_url(self):
  20. return len(self.new_urls) != 0
  21.  
  22. def get_new_url(self):
  23. new_url = self.new_urls.pop()
  24. self.old_urls.add(new_url)
  25. return new_url

html_downloader.py

  1. # coding:utf-8
  2. import urllib.request
  3.  
  4. class HtmlDownloader(object):
  5. def download(self, url):
  6. if url is None:
  7. return None
  8. response = urllib.request.urlopen(url)
  9. if response.getcode() != 200:
  10. return None
  11. return response.read()

html_parser.py

  1. # coding:utf-8
  2. from bs4 import BeautifulSoup
  3. import re
  4. from urllib.parse import urljoin
  5.  
  6. class HtmlParser(object):
  7. def _get_new_urls(self, page_url, soup):
  8. new_urls = set()
  9. # /view/123.htm
  10. links = soup.find_all('a', href=re.compile(r'/view/\d+\.htm'))
  11. for link in links:
  12. new_url = link['href']
  13. new_full_url = urljoin(page_url, new_url)
  14. # print(new_full_url)
  15. new_urls.add(new_full_url)
  16. #print(new_urls)
  17. return new_urls
  18.  
  19. def _get_new_data(self, page_url, soup):
  20. res_data = {}
  21. # url
  22. res_data['url'] = page_url
  23. # <dd class="lemmaWgt-lemmaTitle-title"> <h1>Python</h1>
  24. title_node = soup.find('dd', class_='lemmaWgt-lemmaTitle-title').find('h1')
  25. res_data['title'] = title_node.get_text()
  26. # <div class="lemma-summary" label-module="lemmaSummary">
  27. summary_node = soup.find('div', class_='lemma-summary')
  28. res_data['summary'] = summary_node.get_text()
  29. # print(res_data)
  30. return res_data
  31.  
  32. def parse(self, page_url, html_cont):
  33. if page_url is None or html_cont is None:
  34. return
  35. soup = BeautifulSoup(html_cont, 'html.parser')
  36. # print(soup.prettify())
  37. new_urls = self._get_new_urls(page_url, soup)
  38. new_data = self._get_new_data(page_url, soup)
  39. # print('mark')
  40. return new_urls, new_data

html_outputer.py

  1. # coding:utf-8
  2. class HtmlOutputer(object):
  3. def __init__(self):
  4. self.datas = []
  5.  
  6. def collect_data(self, data):
  7. if data is None:
  8. return
  9. self.datas.append(data)
  10.  
  11. def output_html(self):
  12. fout = open('output.html','w', encoding='utf-8')
  13.  
  14. fout.write('<html>')
  15. fout.write('<body>')
  16. fout.write('<table>')
  17.  
  18. for data in self.datas:
  19. fout.write('<tr>')
  20. fout.write('<td>%s</td>' % data['url'])
  21. fout.write('<td>%s</td>' % data['title'])
  22. fout.write('<td>%s</td>' % data['summary'])
  23. fout.write('</tr>')
  24.  
  25. fout.write('</table>')
  26. fout.write('</body>')
  27. fout.write('</html>')
  28.  
  29. fout.close()

运行

在命令行下,执行python spider_main.py。

编码问题

问题描述:UnicodeEncodeError: ‘gbk’ codec can’t encode character ‘\xa0’ in position …

使用Python写文件的时候,或者将网络数据流写入到本地文件的时候,大部分情况下会遇到这个问题。网络上有很多类似的文章讲述如何解决这个问题,但是无非就是encode,decode相关的,这是导致该问题出现的真正原因吗?不是的。很多时候,我们使用了decode和encode,试遍了各种编码,utf8,utf-8,gbk,gb2312等等,该有的编码都试遍了,可是仍然出现该错误,令人崩溃。

在windows下面编写python脚本,编码问题很严重。将网络数据流写入文件时,我们会遇到几个编码:

1、#encoding=’XXX’

这里(也就是python文件第一行的内容)的编码是指该python脚本文件本身的编码,无关紧要。只要XXX和文件本身的编码相同就行了。

比如notepad++”格式”菜单里面里可以设置各种编码,这时需要保证该菜单里设置的编码和encoding XXX相同就行了,不同的话会报错。

2、网络数据流的编码

比如获取网页,那么网络数据流的编码就是网页的编码。需要使用decode解码成unicode编码。

3、目标文件的编码

将网络数据流写入到新文件,写文件代码如下:

  1. fout = open('output.html','w')
  2. fout.write(str)

在windows下面,新文件的默认编码是gbk,python解释器会用gbk编码去解析我们的网络数据流str,然而str是decode过的unicode编码,这样的话就会导致解析不了,出现上述问题。 解决的办法是改变目标文件的编码:

  1. fout = open('output.html','w', encoding='utf-8')

Python抓取数据具体流程的更多相关文章

  1. python抓取数据,python使用socks代理抓取数据

    在python中,正常的抓取数据直接使用urllib2 这个模块: import urllib2 url = 'http://fanyi.baidu.com/' stream = urllib2.ur ...

  2. 在mac下使用python抓取数据

    2015已经过去,这是2016的第一篇博文! 祝大家新年快乐! 但是我还有好多期末考试! 还没开始复习,唉,一把辛酸泪! 最近看了一遍彦祖的文章叫做 iOS程序员如何使用Python写网路爬虫 所以自 ...

  3. python抓取数据 常见反爬虫 情况

    1.报文头信息: User-Agent Accept-Language  防盗链 上referer 随机生成不同的User-Agent构造报头 2.加抓取等待时间 每抓取一页都让它随机休息几秒,加入此 ...

  4. python抓取数据构建词云

    1.词云图 词云图,也叫文字云,是对文本中出现频率较高的"关键词"予以视觉化的展现,词云图过滤掉大量的低频低质的文本信息,使得浏览者只要一眼扫过文本就可领略文本的主旨. 先看几个词 ...

  5. python 抓取数据,pandas进行数据分析并可视化展示

    感觉要总结总结了,希望这次能写个系列文章分享分享心得,和大神们交流交流,提升提升. 因为半桶子水的水平,一直在想写什么,为什么写,怎么写. 直到现在找到了一种好的办法: 1.写什么 自己手上掌握的,工 ...

  6. python 抓取数据 存入 excel

    import requestsimport datetimefrom random import choicefrom time import timefrom openpyxl import loa ...

  7. Python 抓取数据存储到Mysql中

    # -*- coding: utf-8 -*- import os,sys import requests import bs4 import pymysql#import MySQLdb #连接MY ...

  8. Python 抓取数据存储到Redis中

    redis是一个key-value存储结构.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...

  9. 使用python抓取数据之菜鸟爬虫1

    ''' Created on 2018-5-27 @author: yaoshuangqi ''' #本代码获取百度乐彩网站上的信息,只获取最近100期的双色球 import urllib.reque ...

  10. 使用python抓取并分析数据—链家网(requests+BeautifulSoup)(转)

    本篇文章是使用python抓取数据的第一篇,使用requests+BeautifulSoup的方法对页面进行抓取和数据提取.通过使用requests库对链家网二手房列表页进行抓取,通过Beautifu ...

随机推荐

  1. es 部署 进程、文件数 配置

    1.  /etc/security/limits.conf elasticsearch soft nofile 65536 elasticsearch hard nofile 65536 elasti ...

  2. 空间数据格式(地理数据格式):GeoJSON(FeatureCollection)与EsriJSON(FeatureSet/ArcGIS格式)

    一.FeatureCollection(GeoJSON)格式介绍 https://learn.microsoft.com/en-us/javascript/api/azure-maps-control ...

  3. unity 调试 packages

    package中代码vs无法f12跳转 解决方法 1 把包copy出来 2 Package Manager->Add package from disk 3 选择包文件中的package.jso ...

  4. iverilog_makefile

    makefile run: iverilog -g2005-sv -I ../inc -s tb -f filelist -o kout sim: vvp kout flist: find ../rt ...

  5. CentOS网络服务操作命令

    CentOS 重启网络服务,输入下面的命令:systemctl retart network.service 或 systemctl restart network.CentOS 启动网络服务,输入下 ...

  6. 【Java】【Mybatis】如何调用存储过程和存储函数

    https://www.jb51.net/article/230756.htm Mybatis调用存储过程 MyBatis支持使用存储过程的配置.当使用存储过程时,需要设置一个参数"mode ...

  7. 上传镜像到harbor

    https://blog.csdn.net/weixin_45335305/article/details/123817541

  8. Linux下运行jmeter测试案例

    主要介绍Jmeter脚本如何在Linux通过no GUI的方式运行 一.Linux下JDK的安装及环境变量的配置(可自行百度安装配置流程,window下安装的Jmeter和JDK要和Linux的保持一 ...

  9. 043_关于Salesforce集中权限的解释

    1.创建Object的时候,一定要选中Deploy,避免在All Tabs 中找不到 2.在Profile里,选择 Standart tab Setting.Custom tab setting,有三 ...

  10. python爬虫代码中_获取状态码

    '两种方式' import urllib status=urllib.urlopen("//www.jb51.net").code print status import requ ...