Python3 爬虫
一. 操作系统
操作系统: Windows 或 Linux均可,安装好Python运行环境,加入环境变量即可。
很Linux发行版默认为Python2,需要再安装Python3,步骤:
以CentOS7 下安装 Python3.7为例:
1. 安装依赖包 #yum install zlib* libffi-devel -y 2. 下载 Python-3.7.0 #wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz #tar -zxf Python-3.7.0.tgz #cd Python-3.7.0/ 3. 安装 gcc #yum insatll -y gcc 4. 编译,执行 #./configure --prefix=/usr/local/python3 #make #make install 5. 生成软链接 #ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3 #ln -s /usr/local/python3/bin/python3 /usr/bin/python3/
二. 正则表达式
学习爬虫需要懂得简单的正则表达式的写法:
教程:
零基础写python爬虫之神器正则表达式 >>
三. 第三方库
1. BeautifulSoup
BeautifulSoup是Python的一个库,最主要的功能就是从网页爬取我们需要的数据。BeautifulSoup将html解析为对象进行处理,全部页面转变为字典或者数组,相对于正则表达式的方式,可以大大简化处理过程。
安装
#pip3 install --upgrade beautifulsoup4
BeautifulSoup测试代码:
#filename: bs4_test.py from bs4 import BeautifulSoup html = ''' <html><head><title>The Dormouse's story</title></head> <body> <p class="title"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> ''' soup = BeautifulSoup(html,'html.parser') #soup = BeautifulSoup(html, 'lxml') print(soup.prettify()) print(soup.title) print(soup.title.name) print(soup.title.string) print(soup.title.parent.name) print(soup.p) print(soup.p["class"]) print(soup.a) print(soup.find_all('a')) print(soup.find(id='link3'))
2. lxml
第三方xml解析工具
安装
#pip3 install lxml
四. 写爬虫步骤
1. 要明确爬取的网站结构。
(1)url
爬虫主要解析页面的url, 以及每个url页面的html标签(如head,body, div, p, a等)。首先对所要爬取的页面 url和内容的布局非常了解。
比如爬取凤凰网的所有新闻。 凤凰网大部分新闻正文的页面链接,都是这种形式:
http://news.ifeng.com/a/20170623/51308599_0.shtml
可以用正则表达式把这些页面从新闻首页中提取出来
re_newsdetail = 'http://news\.ifeng\.com\/a\/[0-9]{8}\/[0-9]{8}\_0\.shtml$'
(2)页面中的标签元素
我们主要提取的是新闻的标题和正文内容。 可以在浏览器(chrome)里用F12, 来观察页面布局。
比如凤凰网新闻正文页面, 标题都在<div id='artical'>中,是<h1>标签, 正文都在<div id='main_content'>里, 是<p>标签。
3. 编写程序并调试
urllib负责对url的处理,主要是request, parse, error, 这几个模块。 负责对url发送请求,获取页面信息,error的处理。
Beautifulsoup负责对页面的解析,获取的页面是html树形结构, 通过findAll(), select(), get(), get_text()等函数即可很方便的获取到我们想要的内容。
4.最后,如果是想要获取整个门户网站的数据,则需要一些递归, 整个网站相当于一个图结构, dfs(深度优先遍历)是比较好的方法。
多级递归爬虫示例:
#coding: utf-8 import codecs from urllib import request, parse from bs4 import BeautifulSoup import re import time from urllib.error import HTTPError, URLError import sys ###新闻类定义 class News(object): def __init__(self): self.url = None #该新闻对应的url self.topic = None #新闻标题 self.date = None #新闻发布日期 self.content = None #新闻的正文内容 self.author = None #新闻作者 ###如果url符合解析要求,则对该页面进行信息提取 def getNews(url): #获取页面所有元素 html = request.urlopen(url).read().decode('utf-8', 'ignore') #解析 soup = BeautifulSoup(html, 'lxml') #检查是否是 artical if not(soup.find('div', {'id':'artical'})): return news = News() #建立新闻对象 page = soup.find('div', {'id':'artical'}) #正文及标题 if not(page.find('h1', {'id':'artical_topic'})): return #新闻标题 topic = page.find('h1', {'id':'artical_topic'}).get_text() news.topic = topic if not(page.find('div', {'id': 'main_content'})): return #新闻正文内容 main_content = page.find('div', {'id': 'main_content'}) content = '' #新闻内容 for p in main_content.select('p'): content = content + p.get_text() news.content = content news.url = url #新闻页面对应的url f.write(news.topic+'\t'+news.content+'\n') ##dfs算法遍历全站### def dfs(url): #global count print(url) #可以继续访问的url规则 pattern1 = 'http://news\.ifeng\.com\/[a-z0-9_\/\.]*$' #解析新闻信息的url规则 pattern2 = 'http://news\.ifeng\.com\/a\/[0-9]{8}\/[0-9]{8}\_0\.shtml$' #该url访问过,则直接返回 if url in visited: return print(url) #把该url添加进visited() visited.add(url) try: #该url没有访问过的话,则继续解析操作 html = request.urlopen(url).read().decode('utf-8', 'ignore') ####提取该页面其中所有的url#### links = soup.findAll('a', href=re.compile(pattern1)) for link in links: print(link['href']) if link['href'] not in visited: dfs(link['href']) #递归调用 except URLError as e: print(e) return except HTTPError as e: print(e) return visited = set() ##存储访问过的url f = open('news.txt', 'a+', encoding='utf-8') dfs('http://news.ifeng.com/')
两级爬虫及简单的数据库操作示例:
#coding: utf-8 import codecs from urllib import request, parse from bs4 import BeautifulSoup import re import time from urllib.error import HTTPError, URLError import sys import json import pymysql # 打开数据库连接 connect = pymysql.Connect( host='localhost', port=3306, user='root', passwd='yourpwd', db='yourdb', charset='utf8' ) # 使用cursor()方法获取操作游标 cursor = connect.cursor() # sql语句前半段 sql = "INSERT INTO article(title,author,content,cover,description," \ "publishedtime,cid) VALUES " # 提取新闻内容 def getDetails(url): #获取页面所有元素 html = request.urlopen(url).read().decode('utf-8', 'ignore') #解析 soup = BeautifulSoup(html, 'lxml') #获取信息 if not(soup.find('div', {'id':'artical'})): return page = soup.find('div', {'id':'artical'}) #print('*** analysis page start ***') if not(page.find('h1', {'id':'artical_topic'})): return #新闻标题 topic = page.find('h1', {'id':'artical_topic'}).get_text() if not(page.find('div', {'id': 'main_content'})): return #新闻正文内容 main_content = page.find('div', {'id': 'main_content'}) content = '' if main_content.find('br'): content = main_content.prettify() else: for p in main_content.select('p'): if p.get_text() == '': continue content += "<p>" +p.get_text()+"</p>" content = content.replace("\'","") #每个新闻内容页的js脚本中有一个json格式的新闻简介 #可以提取cover图片,新闻标题,摘要,类别等 for sc in soup.findAll("script"): if '@TODO: 全局参数' in sc.prettify(): try: detail = sc.prettify() detail = detail.replace("\'","\"") jsonStart = findStr(detail, '{', 2) jsonEnd = detail.index('}') detail = detail[jsonStart:jsonEnd] jsonData = json.loads(detail+'}') except: return author = '凤凰网' title = topic content = content desc = jsonData['summary'] publishedtime = str(int(time.time())) cid = '1' cover = jsonData['image'] strSql.add(sql+"('"+title+"', '"+author+"','"+content+"','"+ \ cover+"','"+desc+"',"+publishedtime+","+cid+")") # 遍历新闻主页面 def getNews(url): global count #解析新闻信息的url规则 pattern = 'http://news\.ifeng\.com\/a\/[0-9]{8}\/[0-9]{8}\_0\.shtml$' try: html = request.urlopen(url).read().decode('utf-8', 'ignore') soup = BeautifulSoup(html, 'lxml') # 提取该页面其中所有的url links = soup.findAll('a', href=re.compile(pattern)) count = 1 for link in links: if (count <= 30) : print(link['href']+' **** count: '+str(count)) getDetails(link['href']) count += 1 else: break except URLError as e: print(e) return except HTTPError as e: print(e) return #查找第N(findCnt)次出现的位置 def findStr(string, subStr, findCnt): listStr = string.split(subStr,findCnt) if len(listStr) <= findCnt: return -1 return len(string)-len(listStr[-1])-len(subStr) ############################################################## strSql = set() today = time.strftime('%Y%m%d',time.localtime()) #getDetails('http://news.ifeng.com/a/20180604/58574816_0.shtml') try: getNews('http://news.ifeng.com/listpage/11502/'+today+'/1/rtlist.shtml') for strsql in strSql: # 执行sql语句 cursor.execute(strsql) # 提交到数据库执行 connect.commit() print('成功插入', len(strSql), '条数据') cursor.close() except Exception as e: cursor.close() # 如果发生错误则回滚 connect.rollback() print('事务处理失败', e) # 关闭数据库连接 connect.close()
爬虫效果展示:
多级爬虫参考:https://blog.csdn.net/MrWilliamVs/article/details/76422584?locationNum=9&fps=1ss