Python网络爬虫与信息提取
2021/5/4 14:25:23
本文主要是介绍Python网络爬虫与信息提取,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 单元一 Requests库
- HTTP协议及Requests库方法
- Requests库get()方法
- Requests库的安装
- Requests主要方法
- 爬取网页的通用代码框架
- Robots协议
- robots协议遵守方式
- 网络爬虫引发的问题
- 京东商品页面的爬取
- 百度/360搜索关键词提交
- 网络图片的爬取和存储
- IP地址归属地的自动查询
- BeautifulSoup库安装
- Beautiful Soup库的基本元素
- 基于bs4库的HTML格式输出
- 基于bs4库的HTML内容遍历方法
- 基于bs4库的HTML内容查找方法
- 三种信息标记形式的比较
- 提取信息的一般方法
- 中国大学排名定向爬虫
- Re库的match对象
- Re库的基本使用
- Re库的贪婪匹配和最小匹配
- 正则表达式概念
- 正则表达式的语法
- 淘宝商品比价定向爬虫
- 股票数据定向爬虫
- requests库和Scrapy爬虫比较
- Scrapy爬虫的常用命令
- Scrapy爬虫框架介绍
- Scrapy爬虫框架解析
- Scrapy实例1
- Scrapy爬虫的基本使用
- yield关键字的使用
- 股票数据Scrapy爬虫实例
单元一 Requests库
HTTP协议及Requests库方法
HTTP协议:Hypertext Transfer Protocal,超文本传输协议,基于响应与请求、无状态的应用层协议
HTTP协议采用URL作为定位网络资源的标识
每个URL格式:http://host[:port][path]
host:一个合法的Internet主机域名或IP地址
port:端口号,缺省为80
path:请示资源的路径
URL通过HTTP协议存取资源的Internet路径,一个URL对应一个资源
HTTP协议方法:
PATCH和PUT的区别:
若URL有一组数据UserInfo,包含UserID、UserName等20个字段,要修改UserName,其他不变,PATCH仅向URL提交UserName的局部更新请示,PUT必须要提交所有字段,未提交的字段被删除。所以PATCH方法可以节省带宽
Requests库的post()方法
payload = {'key1':'value1','key2':'value2'} r = requests.post('http://httpbin.org/post',data = payload) print(r.text)
键值对默认存到表单下
r = requests.post('http://httpbin.org/post',data = 'ABC') print(r.text)
字符串自动编码为data
put()方法会覆盖原有的数据
Requests库get()方法
url = 某个网址 r = requests.get(url)
request()构造一个向服务器请求资源的Requests对象
Response返回一个包含服务器资源的Requests对象
requests.get(url,params=None,**kwargs)
url:拟获取页面的url链接
params:url中的额外参数,字典或字节流格式,可选
**kwargs:12个控制访问的参数
Requests库共有7个常用方法,除了requests()方法为基础方法外,其他方法都是调用requests()方法
import requests r = requests.get("http://www.baidu.com") print(r.status_code) type(r) r.headers
状态码为200表示成功
Response对象的属性
import requests r = requests.get("http://www.baidu.com") r.status_code r.encoding r.apparent_encoding r.encoding = 'utf-8' r.text
如果header中不存在charset,encoding则认为编码为ISO-8859-1,它不能解析中文
Requests库的安装
cmd控制台:pip install requests
Requests主要方法
requests.request(method,url,**kwargs)
method:请求方法,如get/put/OPTIONS等7种
url:链接
**kwargs:控制访问参数,13个
r = requests.request('GET',url,**kwargs) r = requests.request('HEAD',url,**kwargs) r = requests.request('POST',url,**kwargs) r = requests.request('PUT',url,**kwargs) r = requests.request('PATCH',url,**kwargs) r = requests.request('delete',url,**kwargs) r = requests.request('OPTIONS',url,**kwargs)
**kwargs:
params:字典或字节序列,作为参数增加到url中
kv = {'key1':'value1','key2':'value2'} r = requests.request('GET','http://python123.io/ws',params=kv) print(r.url)
data:字典、字节序列或文件对象,作为Request的内容
kv = {'key1':'value1','key2':'value2'} r = requests.request('GET','http://python123.io/ws',data=kv) body ='主体内容' r = requests.request('POST','http://python123.io/ws',data = body)
json:JSON格式的数据,作为Reuqest的内容
kv = {'key1':'value1'} r = requests.request('POST','http://python123.io/ws',json= kv)
headers:字典,HTTP定制头
hd={'user-agent':'Chrome/10'} r = requests.request('POST','http://python123.io/ws',headers= hd)
cookies:字典或CookieJar,Request中的cookie
auth:元组,支持HTTP认证
files:字典类型,传输文件
fs = {'file':open('data.xls', 'rb')} r = requests.request('POST','http://python123.io/ws',files= fs)
timeout:设定超时时间,以秒为单位
r = requests.request('GET','http://python123.io/ws',timeout=10)
proxies:字典类型,设定访问代理服务器,可以增加登录认证
pxs = {'http':'http://user:pass@10.10.10.1:1234' 'https':'https://10.10.10.1:4321'} r = requests.request('GET','http://www.baidu.com',proxies=pxs)
allow_redirects:True/False,默认为True,重定向开关
stream:True/False,默认为True,获取内容立即下载开关
verify:True/False,默认为True,认证SSL证书开关
cert:本地SSL证书路径
requests.get(url,params=None,**kwargs)
**kwargs:12个参数,即request中除了params外的其他参数
requests.head(url,**kwargs)
**kwargs:13个参数
requests.post(url,data=None,json=None,**kwargs)
data:字典、字节序列或文件,Request的内容
json:JSON格式的数据,Request的内容
**kwargs:11个参数
requests.put(url,data=None,**kwargs)
data:字典、字节序列或文件,Request的内容
**kwargs:12个参数
requests.patch(url,data=None,**kwargs)
data:字典、字节序列或文件,Request的内容
**kwargs:12个参数
requests.delete(url,**kwargs)
**kwargs:13个参数
爬取网页的通用代码框架
Requests库的异常
import requests def geHTMLText(url): try: r = requests.get(url,timeout=30) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except: return "产生异常" if __name__ == "__main__": url = "http://www.baidu.com" print(getHTMLText(url))
Robots协议
Robots Exclusion Standard 网络爬虫排除标准
robots.txt在网站的根目录下
*表示所有
Disallow: /?*表示所有都不允许访问以?开头的路径
Disallow:/pop/*.html表示所有都不允许访问pop下的所有html
User-agent:EtaoSpider
Disallow: /
表示EtaoSpider不允许爬取任何内容
如果一个网址不提供robots协议,则默认允许所有爬虫爬取
robots协议遵守方式
robots协议是建议但非约束性,不遵守存在法律风险
类人行为可不参考Robots协议,访问量非常小,速度慢
网络爬虫引发的问题
小规模,可用requests库
中规模,数据规格大,速度敏感,可用Scrapy
爬取全网,如搜索引擎,定制开发
网络爬虫的骚扰,服务器崩溃
服务器上的数据有产权归属
爬虫泄露隐私
爬虫限制:
来源审查:判断User-agent
robots协议:告示牌
京东商品页面的爬取
import requests url = "https://item.jd.com/2967929.html" try: r = requests.get(url) r.raise_for_status() r.encoding = r.apparent_encoding print(r.text[:1000]) except: print("爬取失败")
百度/360搜索关键词提交
import requests keyword = "Python" try: kv = {'wd':keyword} r = requests.get("http://www.baidu.com/s",params =kv) print(r.requests.url) r.raise_for_status() print(len(r.text)) except: print("爬取失败")
网络图片的爬取和存储
import requests import os url = "http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg" root ="D://pics//" path = root + url.split('/')[-1] try: if not os.path.exists(roo): os.mkdir(root) if not os.path.exists(path): r = requests.get(url) with open(path,'wb') as f: f.write(r.content) f.close() print("文件保存成功") else: print("文件已存在") except: print("爬取失败")
IP地址归属地的自动查询
import requests url = "http://m.ip138.com/ip.asp?ip=" try: r = requests.get(url+'202.204.80.122') r.raise_for_status() r.encoding = r.apparent_encoding print(r.text[-500:]) except: print("爬取失败")
BeautifulSoup库安装
cmd下,输入pip install beautifulsoup4
html的格式
<html>
<head></head>
<body>
<\body>
</html>
import requests from bs4 import BeautifulSoup r = requests.get("http://python123.io/ws/demo.html") r.text demo = r.text soup = BeautifulSoup(demo,"html.parser") print(soup.prettify())
Beautiful Soup库的基本元素
此库是解析、遍历、维护标签树的功能库
<p class=“title”>…</p>
名称是p
属性是class=“title”
解析器:
基本元素
from bs4 import BeautifulSoup soup = BeautifulSoup(demo,"html.parser") soup.title tag = soup.a tag.attrs tag.attrs['class'] tag.attrs['href'] type(tag.attrs) type(tag) soup.a.name soup.a.parent.name soup.a.parent.parent.name soup.a.string soup.p soup.p.string type(soup.p.string) newsoup = BeautifulSoup("<b>--Tis is a comment</b><p>This is not a comment</p>","html.parser") newsoup.b.string type(newsoup.b.string) newsoup.p.string type(newsoup.p.string)
基于bs4库的HTML格式输出
from bs4 import BeautifulSoup soup = BeautifulSoup(demo,"html.parser") soup.prettify() print(soup.prettify())
基于bs4库的HTML内容遍历方法
标签树的下行遍历
soup = BeautifulSoup(demo,"html.parser") soup.head soup.head.contents soup.body.contents len(soup.body.contents) soup.body.contents[1]
上行遍历
soup = BeautifulSoup(demo,"html.parser") soup.title.parent soup.html.parent soup.parent
上行遍历
soup = BeautifulSoup(demo,"html.parser") for parent in soup.a.parents: if parent is None: print(parent) else: print(parent.name)
平行遍历
平行遍历发生在同一父节点下的各节点间
soup = BeautifulSoup(demo,"html.parser") soup.a.next_sibling soup.a.next_sibling.next.sibling soup.a.previous_sibling soup.a.previous_sibling.previous_sibling soup.a.parent
基于bs4库的HTML内容查找方法
<>.find_all(name,attrs,recursive,string,**kwargs)
返回一个列表类型,存储结果
name:对标签名称的检索字符串
attrs:对标签属性值的检索字符串,可标注属性检索
recursive:是否对子孙全部检索,默认是True
string:<>…</>中字符串区域的检索字符串
soup.find_all('a') soup.find_all(['a','b'])
若只给True,则返回所有标签
for tag in soup.find_all(True): print(tag.name)
soup.find_all('p','course')
精准查找:
soup.find_all(id='link1')
模糊查找:正则表达式
soup.find_all(string = "Basic Python")
简写:
<tag>()等价于<tag>.find_all()
扩展方法
三种信息标记形式的比较
XML:eXtensible Markup Language
用<>标记
<name>…</name>
JSON:JavaScript Object Notation
用有类型键值对标记
“key”:“value”
“key”:[“value1”,“value2”]
“key”:{“value1”,“value2”}
YAML:YAML Ain’t Markup Language
无类型键值对标记
firstName:xxx
lastName:XXX
XML:有效信息占比不高,大部分信息被标签占用,可用于Internet
JSON:比XML简洁,用于移动端或程序,无法体现注释
YAML:有效信息利用率最高,用于系统配置文件,有注释
提取信息的一般方法
一:完整解析后再提取关键信息
二:无视标记形式,直接搜索关键信息
from bs4 import BeautifulSoup soup = BeautifulSoup(demo,"html.parser") for link in soup.find_all('a'): print(link.get('href'))
中国大学排名定向爬虫
import requests import bs4 from bs4 import BeautifulSoup def getHTMLText(url): try: r = requests.get(url,timeout=30) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except: return "" def fillUnivList(ulist, html): soup = BeautifulSoup(html, "html.parser") for tr in soup.find('tbody').children: if isinstance(tr,bs4.element.Tag): tds = tr('td') ulist.append([tds[0].string,tds[1].string,tds[2].string]) def printUnivList(ulist, num): print("{:^10}\t{:^6}\t{:^10}".format("排名","学校名称","总分")) for i in range(num): u=ulist[i] print("{:^10}\t{:^6}\t{:^10}".format(u[0],u[1],u[2])) def main(): uinfo = [] url = "http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html" html = getHTMLText(url) fillUnivList(uinfo, html) printUnivList(uinfo, 20) main()
Re库的match对象
Match对象是一次匹配的结果,有type(match)将返回<class ‘_sre.SRE_Mathc’>
Match对象的属性
Match对象的方法
import re m = re.search(r'[1-9]\d{5}','BIT10081 TSU100084') m.string m.re m.pos m.endpos m.group(0) m.start() m.end() m.span()
Re库的基本使用
用于字符串匹配
raw string类型(原生字符串类型),表达为r’text’,它不包含转义符的字符串,比如\\仅用\表示
Re库主要功能函数
re.search(pattern,string,flags=0)
pattern:正则表达式字符串
string:待匹配的字符串
flags:正则表达式使用时的控制标记
import re m = re.search(r'[1-9]\d{5}','BIT 10081') if match: print(match.group(0))
re.match(pattern,string,flags=0)
import re match = re.match(r'[1-9]\d{5}','BIT 10081') if match: match.group(0) match = re.match(r'[1-9]\d{5}','10081 BIT') if match: match.group(0)
match可以返回空,调用group会出错
re.findall(pattern,string,flags=0)
搜索字符串,以列表类型返回全部能匹配的子串
import re ls = re.findall(r'[1-9]\d{5}','BIT10081 TSU100084') ls
re.split(pattern,string,maxsplit=0,flags=0)
将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
import re re.split(r'[1-9]\d{5}','BIT10081 TSU100084') re.split(r'[1-9]\d{5}','BIT10081 TSU100084',maxsplit=1)
re.finditer(pattern,string,flags=0)
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
import re for m in re.finditer(r'[1-9]\d{5}','BIT10081 TSU100084'): if m: print(m.group(0))
re.sub(pattern,repl,string,count=0,flags=0)
在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
Re库的贪婪匹配和最小匹配
Re库默认采用贪婪匹配,即输出匹配最长的子串
match = re.search(r'PY'.*N','PYANBNCNDN') match.group(0)
最小匹配
match = re.search(r'PY'.*?N','PYANBNCNDN') match.group(0)
最小匹配操作符
正则表达式概念
regular expression
regex
re
正则表达式是用来简洁表达一组字符串的表达式
通用的字符串表达框架
简洁表达一组字符串的表达式
针对字符串表达“简洁”和“特征”思想的工具
判断某字符串的特征归属
正则表达式的语法
abc*:表示*前面的c可以出现0次或无限次,如ab,abc,abcc,…
abc+:表示+前面的c可以出现1次或无限次,如abc,abcc…
IP地址的正则表达式
淘宝商品比价定向爬虫
import requests import re def getHTMLText(url): try: r = requests.get(url, timeout = 30) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except: return "" def parsePage(ilt,html): try: plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"',html) tlt = re.findall(r'\"raw_title\"\:\".*?\"',html) for i in range(plt): price = eval(plt[i].split(':')[1]) title = eval(title[i].split(':')[1]) ilt.append([price,title]) except: print("") def printGoodsList(ilt): tplt = "{:4}\t{:8}\t{:16}" print(tplt.format("序号","价格","商品名称")) count = 0 for g in ilt: count = count + 1 print(tplt.format(count,g[0],g[1])) def main(): goods = "书包" depth = 2 start_url = 'https://s.taobao.com/search?q='+goods infoList = [] for i in range(depth): try: url = start_ulr+'&s='+str(44*i) html = getHTMLText(url) parsePage(infoList, html) except: continue printGoodsList(infoList) main()
股票数据定向爬虫
import requests from bs4 import BeautifulSoup import traceback import re def getHTMLText(url): try: r = requests.get(url, timeout = 30) r.raise_for_status() r.encoding = r.apparent_encoding return r.txt except: return "" def getStockList(lst, stockURL): html = getHTMLText(stockURL) soup = BeautifulSoup(html, 'html.parser') a = find_all('a') for i in a: try: href = i.attrs['href'] lst.append(re.findall(r"[s][hz]\d{6})",href)[0]) except: continue def getStockInfo(lst, stockURL, fpath): for stock in lst: url = stockURL + stock + ".html" html = getHTMLText(url) try: if html == "": continue infoDict = {} soup = BeautifulSoup(html,'html.parser') stockInfo = soup.find('div',attrs={'class':'stock-bets'}) name = stockInfo.find_all(attrs={'class':'bets-name'})[0] infoDict.update({'股票名称':name.text.split()[0]}) keyList = stockInfo.find_all('dt') valueList = stockInfo.find_all('dd') for i in range(len(keyList)): key = keyList[i].text val = valueList[i].text infoDict[key] = val with open(fpath, 'a',encoding = 'utf-8') as f: f.write(str(infoDict) + '\n')y except: traceback.print_exc() continue def main(): stock_list_url = 'http://quote.eastmoney.com/stocklist.html' stock_Info_url = 'http://gupiao.baidu.com/stock/' output_file = 'D://BaiduStockInfo.txt' slist = [] getStockList(slist, stock_list_url) getStockInfo(slist, stock_info_url, output_file) main()
requests库和Scrapy爬虫比较
相同点:
都可以进行页面请求和爬取
可用性好
没有处理js,提交表单
不同:
requests:页面级爬虫,功能库,并发性不足,页面下载,定制灵活,简单
Scrqpy:网站级爬虫,框架,并发性好,爬虫结构,深度定制困难,稍难
Scrapy爬虫的常用命令
Scrapy命令行格式
>scrapy<command>[options][args]
常用命令
命令行更容易自动化,适合脚本控制
本质上,Scrapy是给程序员用的,功能更重要
Scrapy爬虫框架介绍
爬虫框架是实现爬虫功能的一个软件结构和功能组件集合
爬虫框架是一个半成品,能帮助用户实现专业网络爬虫
Scrapy爬虫框架解析
Engine:控制抽有模块之间的数据流;根据条件触发事件(不需要用户修改)
Downloader:根据请求下载网页(不需要用户修改)
Scheduler:对所有爬虫请求进行调度管理(不需要用户修改)
Downloader Middleware:修改、丢弃、新增请求或响应
Spider:解析Downloader返回的响应;产生爬取项;产生额外的爬取请求
Item Pipelines:以流水线方式处理Spider产生的爬取项;由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型;清理、检验和查重爬取项中的HTML数据,将数据存储到数据库(需要用户编写)
Spider Middleware:修改、丢弃、新增请求或爬取项
Scrapy实例1
安装好Scrapy库后
打开命令提示符
输入d:
输入cd pycodes
输入scrapy startproject python123demo
scrapy.cfg:部署Scrapy爬虫的配置文件
python123demo:Scrapy框架的用户自定义Python代码
_init_.py:初始化脚本
items.py:Items代码模板(继承类)
middlewares.py:Middlewares代码模板(继承类)
pipelines.py:Pipelines代码模块(继承类)
settings.py:Scrapy爬虫的配置文件
输入scrapy genspider demo python123.io
增加了一个新的文件demo.py,内容如下
# -*- coding: utf-8 -*- import scrapy class DemoSpider(scrapy.Spider): name = "demo" allowed_domains = ["python123.io"] start_urls = ['http://python123.io/'] def parse(self, response): pass
parse()用于处理响应,解析内容形成字典,发现新的URL爬取请求
修改demo.py
# -*- coding: utf-8 -*- import scrapy class DemoSpider(scrapy.Spider): name = "demo" #allowed_domains = ["python123.io"] start_urls = ['http://python123.io/ws/demo.html'] def parse(self, response): fname = response.url.split('/')[-1] with open(fname, 'wb') as f: f.write(response.body) self.log('Save file %s.' %name)
输入scrapy crawl demo
Scrapy爬虫的基本使用
创建一个工程和Spider模板
编写Spider
编写Item Pipeline
优化配置策略
Requests类
Response类
Item类
Scrapy爬虫提取信息的方法
BeautifulSoup
lxml
re
XPath Selector
CSS Selector
yield关键字的使用
生成器是一个不断产生值的函数
包含yield语句的函数是一个生成器
生成器每次产生一个值,函数被冻结,被唤醒后再产生一个值
def gen(n): for i in range(n): yield i**2
股票数据Scrapy爬虫实例
建立工程和Spider模板
编写Spider
编写ITEM Pipelines
输入:
scrapy startproject BaiduStocks
cd BaiduStocks
scrapy genspider stocks baidu.com
修改spiders/stocks.py
# -*- coding: utf-8 -*- import scrapy import re class StockSpider(scrapy.Spider): name = "stocks" start_urls = ['http://quote.eastmoney.com/stocklist.html'] def parse(self, response): for href in response.css('a::attrs(href)').extract(): try: stock = re.findall(r"[s][hz]\d{6}",href)[0] url = 'https://gupiao.baidu.com/stock/' + stock + '.html' yield scrapy.Request(url, callback=self.parse_stock) except: continue def parse_stock(self, response): infoDict = {} stockInfo = response.css('.stock-bets') name = stockInfo.css('bets-name').extract[0] keyList = stockInfo.css('dt').extract() valueList = stockInfo.css('dd').extract() for i in range(keyList): key = re.findall(r'>.*</dt>',keyList[i])[0][1:-5] try: val = re.findall(r'\d+\.?.*</dd>',valueList[i])[0][0:-5] except: val ='--' infoDict[key]=val infoDict,update( {'股票名称':re.findall('\s.*\(',name)[0].split()[0] + \ re.findall('\>.*\<',name)[0][1:-1]}) yield infoDict
修改pipelines.py文件
class BaidustockPipeline(object): def process_item(self, item, spider): return item class BaidustocksInfoPipeline(object): def open_spider(self,spider): self.f = open('BaiduStockInfo.txt','w') def close_spider(self, spider): self.f.close() def process_item(self, item, spider): try: line = str(dict(item) + '\n' self.f.write(line) except: pass return item
修改settings.py,找到一个参数ITEM_PIPELINES
ITEM_PIPELINES = { 'BaiduStocks.pipelines.BaidustocksInfoPipeline':300, }
执行:scrapy crawl stocks
这篇关于Python网络爬虫与信息提取的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-03用FastAPI掌握Python异步IO:轻松实现高并发网络请求处理
- 2025-01-02封装学习:Python面向对象编程基础教程
- 2024-12-28Python编程基础教程
- 2024-12-27Python编程入门指南
- 2024-12-27Python编程基础
- 2024-12-27Python编程基础教程
- 2024-12-27Python编程基础指南
- 2024-12-24Python编程入门指南
- 2024-12-24Python编程基础入门
- 2024-12-24Python编程基础:变量与数据类型