网络爬虫与信息提取笔记
学习python的视频https://www.bilibili.com/video/av69060979?p=1
以爬虫视角,看待网络内容(来源:学习强国平台,北京理工大学学习视频 北京理工大学崇天)
1 Requests库入门
1.1 requests库方法
requests.request() | requests.put() |
---|
requests.get() | requests.patch() | requests.head() | requests.delete() | requests.post() | |
1.2 爬取网页的通用代码框架
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.enconding = r.apparent_encoding
return r.text
except:
return "产生异常"
1.3Request库网络爬虫实战(5个实例)
1.3.1访问京东商品
import requests
url ="http://item.jd.com/2967929.html"
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:100])
except:
print("爬取失败")
1.3.2亚马逊商品页面的爬取
import requests
url = "https://www.amazon.cn/gp/product/B01M8L5Z3Y"
try:
kv = {'user-agent':'Mozilla/5.0'}
r = requests.get(url,headers = kv)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[1000:2000])
except:
print("爬取失败")
1.3.3百度/360搜索关键词提交
提供关键词,得到搜索结果
百度的关键词接口:http://www.baidu.com/s?wd=keyword
360的关键词接口:http://www.so.com/s?q=keyword
import requests
keyword = 'python'
try:
kv = {'wd':keyword}
r = requests.get("http://www.baidu.com/s",params=kv)
print(r.request.url)
r.raise_for_status()
print(len(r.text))
except:
print("爬取失败")
1.3.4网络图片的爬取与存储
网络图片链接的格式:http://www.example.com/picture.jpg
http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg
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(root):
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("爬取失败")
类似的url,网上的视频、图片、动画、flash都可以用这个框架爬取
1.3.5 IP地址归属地的自动查询
比如某一个IP地址是来自北京,上海还是?怎么查询一个地址的归属,一个ip138的网站 http://www.ip138.com/ 提供人查询。
用python程序判断:
http://m.ip138.com/ip.asp?ip=ipaddress url接口,通过提交ip地址到前面这个网页获取归属地
import requests
url = "http://m.ip138.com/ip.asp?ip="
try:
r = requests.get(url+'202.204.80112')
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[-500])
except:
print("爬取失败")
2 网络爬虫的“盗亦有道”
2.1网络爬虫的尺寸
小规模数据量较小,爬取数据不敏感, Requests库 | 中规模,数据规模较大,爬取速度敏感 Scrapy库 | 大规模,搜索引擎,爬取速度关键 定制开发 |
---|
爬取网页,玩转网页 | 爬取网站,爬取系列网站 | 爬取全网 |
2.2网络爬虫引发的问题
骚扰问题、法律风险、泄露隐私
2.3网络爬虫的限制
*来源审查:判断User-Agent进行限制
*发布公告:Robots协议
2.4Robots协议
2.4.1Robots协议基本语法
robots.txt(符合Robots 协议 (又称:爬虫协议、机器人协议等,全称:“网络爬虫排除标准”))是爬虫访问目标网站时查看的第一个文件,他会限定网络爬虫的访问范围。如果文件存在,则爬虫会按照该文件的内容确定访问的范围,否则,爬虫能访问所有没有密码保护的页面。
#注释:*代表所有,/代表根目录
User-Agent: *
Disallow: /
记录 | 作用 |
---|
User-Agent | 描述搜索引擎(爬虫)的名字,至少一个。若其值为“ * ”,则表示该协议对任何搜索引擎都有效,且这样的记录只有一条 | Disallow | 描述不希望被访问的URL,可以是完整路径,也可以是部分路径。任何一条该类记录为空,说明该网站的所有部分都可访问。在robots.txt文件中,至少有一条该类记录 | Allow | 描述希望被访问的URL,与 Disallow 类似。一个网站的所有 URL 默认Allow,所以通常与 Disallow 搭配使用,实现允许访问已备份网页的同时,禁止访问其他所有 URL 的功能 |
2.4.2Robots协议的理解
类人行为可以不参考Robots协议
3 解析HTML页面信息标记与提取方法 Beautiful Soup
3.1 beautifu souo(美味汤)对html进行解析,并提取相关信息。
页面网址:https://python123.io/ws/demo.html
from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data<p>','html.parser')
3.2Beautiful Soup (bs4)库的理解
解析、遍历、维护“标签树”的功能库
将标签树转换为BeautifulSoup类
3.2.1Beautiful Soup库解析器
解析器 | 使用方法 | 条件 |
---|
bs4的HTML解析器 | BeautifulSoup(mk,‘html.parser’) | 安装bs4库 | lxml的HTML解析器 | BeautifulSoup(mk,‘lxml’) | pip install lxml | lxml的HTML解析器 | BeautifulSoup(mk,‘xml’) | pip install lxml | lxml5lib的HTML解析器 | BeautifulSoup(mk,'html5lib) | pip install html5lib |
3.3.获取tag标签内容,名字,属性
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
print(soup.title)
tag = soup.a
print(tag)
print(soup.a.name)
print(soup.a.parent.name)
tag = soup.a
print(tag.atts)
print(tag.attrs['class'])
print(tag.attrs['href'])
print(soup.a.string)
print(soup.p.string)
newsoup = BeautifulSoup("<b><!--This is a comment--></b>")
print(newsoup.p.string)
3.4基于bs4库的遍历方法
3.4.1标签树的下行遍历
属性 | 说明 |
---|
.content | 子节点列表,将标签所有儿子节点存入列表 | .children | 子节点的迭代类型,与.content类似,用于循环遍历儿子节点 | .descendants | 子孙节点的迭代类型,包含所有的子孙节点 |
for chlid in soup.body.children:
print(child)
for child in soup.body.children:
print(child)
3.4.2标签树的上行遍历
属性 | 说明 |
---|
.parent | 节点的父亲标签 | .parents | 节点先辈标签的迭代类型,用于循环遍历先辈节点 |
3.4.3标签树的平行遍历
属性 | 说明 |
---|
.next_sibling | 返回按照HTML文本顺序的下一个平行节点标签 | .previous_sibling | 返回按照HTML文本顺序的上一个平行节点标签 | .next_sibling | 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签 | .previous_sibling | 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签 |
for sibling in soup.a.next_siblings:
print(sibling)
for sibling in soup.a.previous_siblings:
print(sibling)
3.5基于bs4库的HTML格式输出
如何让HTML内容更加友好的显示?
输出美化:prettify()方法
通常BeautifulSoup解析得到的Beautifulsoup对象格式较杂乱,可在输出时使用 **prettify() **方法对BeautifulSoup对象进行美化(为标签和内容添加换行符和缩进,以便于更友好直观地显示HTML内容),示例如下:
print(soup.prettify())
4 信息组织与提取
4.1信息标记形式
4.1.1 XML :eXtensible Markup Language
XML尖括号、标签表达信息的标记形式(html属于XML)
最早的标记语言,相当繁琐
Internet上的信息交互与传递
4.1.2 JSON : JavaScript Object Notation
JSON 有类型的键值对标记
信息有类型,适合程序处理,较XML简洁
移动云端和节点的信息通信,无注释
4.1.3 YAML :YAML Ain’t Markup Language
无类型的键值对标记
信息无类型,文本信息比例最高,可读性非常好
各类系统的配置文件,有注释且移动
4.2信息组织与提取方法
方法一:完整解析信息的标记形式,再提取关键信息
解析格式 XML JSON YAML?
需要标记解析器 例如:bs4
优点:信息解析准确
缺点:提取过程繁琐,速度慢
方法二:无视标记形式,直接搜索关键信息
搜索
对信息文本查找函数即可
优点:提取过程简洁,速度较快
缺点:提取结果准确性与信息内容相关
实例:提取HTML中所有的URL标签
如何提取,融合方法一方法二
思路:1)搜索到所有的标签
? 2)解析标签格式,提取href后的链接内容·。
from bs4 import BeaytifulSoup
soup = BeautifulSoup(demo,"html.parser")
for link in soup.find_all('a'):
print(link.get('href'))
4.3基于bs4库的HTML内容的查找方法
网页中的信息都存在于网页的文本或者各种不同标签的属性值,为获得这些有用的网页信息,可通过一些查找方法获取文本或标签属性。bs4 库内置一些查找方法,其中最常用的两个方法功能如下:
方法 | 功能 |
---|
find() | 查找符合查询条件的第一个标签节点 | find_all() | 查找所有符合查询条件的标签节点,并返回一个列表 |
这两个方法的参数相同,以find_all() 为例,介绍该方法中参数的作用,find_all() 定义如下:
find_all(self,name=Nobe,attrs={key:value},recursive=True,text=None,limit=None,**kwargs)
上述方法中的一些重要参数含义如下:
4.1. name 参数
查找所有名字为name的标签,但**‘name=’**字符串会被忽略.以下是name参数的几种情况:
传入字符串
在搜索的方法中传入一个字符串,BeautifulSoup 对象会查找与字符串完全匹配的内容.例如:
soup.find_all('b')
?```
如果传入一个正则表达式,那么BeautifulSoup对象会通过re模块的match()函数进行匹配.例如:
?```python
soup.find_all(re.compile("^b"))
?```
如果传入一个列表,那么BeautifulSoup对象将会与列表中任意元素匹配的内容返回.例如:
soup.find_all([“a”,“b”]) #返回文档中所有标签和标签
如果某个指定名字的参数不是搜索方法中内置的参数名,那么在进行搜索时,会把该参数当作指定名字的标签中的属性搜索.例如:
?```python
soup.find_all(id='link2')#在find_all()方法中传入名称为id,值为link2的参数,此时BeautifulSoup对象会搜索每个标签的属性
若传入的参数属于Python保留字(如: class),可以在保留字后添加一条下划短线.例如:
soup.find_all(class_='sister')
4.2attrs参数
对标签属性值的检索字符串,可标注属性检索
soup.find_all('p','course')
soup.find_all(id='link1')
若传入多个指定名字的参数,则可同时过滤出标签中的多个属性.例如:
import re
soup.find_all(href=re.compile("elsie"),id='link1')
4.3recursive参数
是否对子孙全部检索,默认True
4.4string参数
标签之间的内容
soup.find_all(string = "Basic Python")
import re
soup.find_all(string = re.compile("python"))
4.5简短模式
(…)等价于.find_all(…)
soup(…)等价于soup.find_all(…)
5.实例中国大学排名爬虫
功能描述
输入:大学排名URL链接http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html
输出:大学排名信息的屏幕输出(排名,大学名称,总分)
技术路线:requests-bs4
定向爬虫:仅对输入url进行爬取,不扩展爬取
程序的结构设计
步骤1:从网络上获取大学排名网页内容
getHTMLText()
步骤2:提取网页内容中信息到合适的数据结构
fillUnivList()
步骤3:利用数据结构展示并输出结果
printUnivList()
二维的数据结果,采取列表的方式
写结构框架
import requests
from bs4 import BeautifulSoup
import bs4
def getHTMLText(url):
return ""
def fillUnivList(ulist,html):
pass
def printUnivList(ulist,num):
print("Suc" + str(num))
def main():
uinfo = []
url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html '
html = getHTMLText(url)
fillUnivList(uinfo,html)
printUnivList(uinfo,20)
main()
所要提取信息的源代码html,观察
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[3].string])
pass
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])
print("Suc" + str(num))
第一次运行错误出现输出错误
print("(:^10)\t(:^6)\t(:^10)".format("排名","学校名称","总分"))
正确输出结果
查询python花括号{}的用法:https://blog.csdn.net/qq_35736437/article/details/90052253
代表dict字典数据类型,字典是Python中唯一内建的映射类型。字典中的值没有特殊的顺序,但都是存储在一个特定的键(key)下。键可以是数字、字符串与元祖。
示例
dic = {‘jay’:‘boy’,‘may"’:‘girl’} dic {‘jay’: ‘boy’, ‘may’: ‘girl’} ———————————————— 原文链接:https://blog.csdn.net/qq_35736437/article/details/90052253
中文对齐问题的解决
当中文字符宽度不够时,采用西文字符填充;中西文字符占用宽度不同
采用中文字符的空格填充chr(12288)
tplt = "{0:^10}\t{1:{3}^10\t{2:^10}}"
print(tplt.format("排名","学校名称","总分",char(12288))
正确输出
6 正则表达式库(re)入门
正则表达式 regular expression regex RE
优势:简洁,一行胜千言
re库是Python的标准库,主要应用于字符串匹配表达中,由字符和操作符构成,调用方法import re
正则表达式的表示类型:
raw string 类型(原生字符串类型:不包含转义符/的字符串)
re库采用raw string类型表示正则表达式,表示为:r'text'
例如:r'[1-9]\d{5}'
re*(支持正则表达式)模块一般使用步骤:
(1) 使用compile() 函数将正则表达式以字符串形式编译为一个Pattern 类型的对象。
(2) 通过Pattern 对象提供的一系列方法对文本进行查找或替换,得到一个处理结果。
(3) 使用处理结果提供的属性和方法获取信息,如匹配到的字符串。
正则表达式关于中文的匹配
大多数情况下,从网站爬取的网页源码都会有汉字,如果要匹配这些汉字,就需要知道其对应的正则表达式,通常情况下,中文对应的Unicode编码范围为**[u4e00-u9fa5a]** 这个范围不包括全角(中文)标点,但大多数情况是可以使用的。
6.1正则表达式常见字符及其含义
https://tool.oschina.net/uploads/apidocs/jquery/regexp.html
操作符 | 说明 | 实例 |
---|
. | 表示任何单个字符 | | [] | 字符集,对单个字符给出取值范围 | [abc]表示a,b,c[a-z]表示a到z单个字符 | [^] | 非字符集,对单个字符给出排除范围 | [^abc]表示非a或b或c的单个字符 | * | 前一个字符0次或无限次扩展 | abc*表示ab,abc,abcc等 | + | 前一个字符1次或无限次扩展 | abc+表示abc,abcc,abccc等 | ? | 前一个字符0次或1次扩展 | abc?表示ab,abc | | | 左右表达式任意一个 | abc|def表示abc,def | {m} | 扩展前一个字符m次 | ab{2}c表示abbc | {m,n} | 扩展前一个字符m至n次(含n) | ab{1,2}c表示abc,abcc | ^ | 匹配字符串开头 | ^abc表示abc且在一个字符串的开头 | $ | 匹配字符串结尾 | abc$表示一个字符串的结尾 | () | 分组标记,内部只能使用|操作符 | (abc)表示abc,(abc|def)表示abc,def | \d | 数字,等价于[0-9] | | \w | 单词字符,等价于[A-Za-z0-9_] | |
6.2正则表达式语法实例
正则表达式 | 对应字符串 |
---|
P(Y|YT|YTH|YTHO)?N | ‘PN’,‘PYN’,‘PYTN’,‘PYTHN’,‘PYTHON’ | PYTHON+ | ‘PYTHON’,‘PYTHONN’,‘PYTHONNN’… | PY[TH]ON | ‘PYTON’,‘PYTHON’ | PY[^TH]?ON | ‘PYON’,‘PYaON’,‘PYbON’,‘PYcON’… | PY{:3}N | ‘PN’,‘PYN’,‘PYYN’,‘PYYYN’ |
6.3正则表达式编译标志及其含义
匹配模式常用在编译正则表达式时,作用涉及 区分大小写、忽略非法字符等。
正则表达式的模式时可以同时使用多个的,在Python里使用 | 同时添加多个模式
匹配模式flages | 说明 |
---|
re.I | 忽略大小写 | re.L | 字符集本地化,该功能是为了支持多语言版本的字符集使用环境。比如‘\w’在英文环境下,代表匹配字母数字,但在法语环境下,缺省设置导致不能匹配法语字符,加上该选项就可匹配。但该选项仍对中文不友好,不能匹配中文字符。 | re.M | 多行模式,改变 ^ 和 $ 的行为 | re.S | 点任意匹配模式,此模式下,‘.’的匹配不受限制,可匹配包括换行符在内的任何字符 | re.X | 冗余模式(详细模式),此模式忽略正则表达式中的空白字符和#的注释(注释与表达式可多行书写) | re.U | 使用\w,\W,\b,\B 这些元字符时将按照Unicode定义的属性 |
6. 正则表达式常用函数
函数 | 用法详解 |
---|
re.compile(pattern,flags=0) | 该方法通常用作以下其他方法的基础。给定一个正则表达式pattern,默认flag = 0,表示不使用任何模式。 | re.match(pattern,string,flags=0) | 从给定字符串起始位置进行匹配,匹配成功则返回匹配结果<_sre.SRE_Match object;span=(0,匹配成功的子串在字符串中的结束位置),match=‘[匹配的子串]’>否则返回None | re.search(pattern,string,flags=0) | 扫描整个字符串返回第一个匹配成功的结果 | re.findall(pattern,string,flags=0) | 扫描整个字符串,以列表的形式返回所有匹配成功的结果 | re.split(pattern,string,maxsplit=0,flag=0) | 使用pattern寻找切分字符串的位置,返回包含切分后子串的列表,若匹配不到,则返回包含原字符串的一个列表。maxsplit 最大分割数 | re.sub(pattern,repl,string,count=0,flags=0) | 替换函数,将正则表达式pattern匹配到的子串替换为repl指定的字符串,count 用于指定最大替换次数 | fre.finditer() | 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
其他函数参考:https://www.cnblogs.com/dyfblog/p/5880728.html
6.4Re库的另一种等价用法
rst = re.search(r'[1-9]\d{5},'BIT 10086')
regex = re.complie(r'[1-9]\d{5}')
rst = regex.search('BIT 10081')
6.5Re库的Match对象(一次匹配的结果)
Match对象的属性
属性 | 说明 |
---|
.string | 待匹配的文本 | .re | 匹配时使用的pattern对象(正则表达式) | .pos | 正则表达式搜索文本的开始位置 | .endpos | 正则表达式搜索文本的结束位置 |
Match对象的方法,详见6.6
方法 | 说明 |
---|
.group(0) | 获得匹配后的字符串 | .start() | 匹配字符串在原始字符串的开头位置 | .end() | 匹配字符串在原始字符串的结束位置 | .spand() | 返回(.start(),.end()) |
>>>import re
>>>m = re.search(r'[1-9]\d{5}','BIT10081 TSU100084')
>>>m.string
'BIT10081 TSU100084'
>>>m.re
re.compile('[1-9]\d{5}')
>>>m.pos
0
>>>m.group(0)
'100081'
>>>m.span()
(3,9)
>>>m.start()
3
贪婪匹配
re库默认采用贪婪匹配,即输出匹配最长的子串
>>>match = re.search(r.'PY.*
N','PYANBNCNDN')
>>>match.group(0)
'PYANBNCNDN'
如何输出最小匹配?在操作符后面增加一个问号
最小匹配操作符
操作符 | 说明 |
---|
*? | 前一个字符0次或无限次扩展,最小匹配 | +? | 前一个字符1次或无限次扩展,最小匹配 | ?? | 前一个字符0次或1次扩展,最小匹配 | {m,n}? | 扩展前一个字符m至n次(含n),最小匹配 |
6.6 正则表达式常用方法
方法 | 说明 |
---|
group([group1,group2….]) | 获得一个或多个分组截获的字符串;指定多个参数时将以元组的形式返回。group1可使用编号或者别名,默认返回group(0),即整个匹配的子串。没有截获字符串的组返回None | groups([default]) | 以元组的形式返回全部分组接获的字符串。相当于调用group(1,2,…last),default表示没有接货字符串德祖以这个值替代,默认为None | groupdict([default]) | 返回以有别名的组的别名为键,以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上 | end([group]) | 返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1).group默认为0 | start([group]) | 返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认为0 | span([group]) | 返回(start(group),end(group)) | expand(template) | 将匹配到的分组带入template中饭后返回。template可使用\id或\g、\g引用分组,但不能使用编号0.\id与\g等价,但\10将被认为是第10个分组,如果想表达\1之后是字符‘0’,只能使用\g<1>0 |
关于正则表达式更完整内容:https://www.cnblogs.com/dyfblog/p/5880728.html
正则表达式Python官方文档:https://docs.python.org/2/howto/regex.html#compiling-regular-expressions
正则表达式30分钟教程:https://www.jb51.net/tools/zhengze.html
7 淘宝商品比价定向爬虫实例
功能描述
目标:获取淘宝搜索页面的信息,提取其中的商品,提取其中的商品名称和价格。
理解:淘宝的搜索接口
? 翻页的处理
技术路线:requests-re
观察接口
定向爬虫可行性,淘宝搜索页面不允许任何爬虫访问,如果个人对淘宝具有相同的频率,不要不加限制的爬取这个网占是可行的
程序的结构设计
步骤1:提交商品搜索请求,循环获取页面。
步骤2:对于每个页面,提取商品名称和价格信息。
步骤3:将信息输出到屏幕上。
写框架
import requests
import re
def getHTMLText(url):
print("")
def parsePage(ilt,html):
print("")
def printGoodsList(ilt):
print("")
def main():
goods = '书包'
depth = 2
start_url = 'https://s.taobao.com/search?q=' + goods
infoList = []
for i in range(depth):
try:
url = start_url + '&s=' + str(44*i)
html = def getHTMLText(url)
getHTMLText(infoList,html)
except:
continue
printGoodsList(infoList)
main()
写函数内容
通过观察网页源代码,发现任何商品的价格有一个raw_price字段来标识,而商品名字用raw_title字段标识
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(len(plt)):
price = eval(plt[i].split(':')[1])
title = eval(tlt[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_url + '&s=' + str(44*i)
html =getHTMLText(url)
parsePage(infoList,html)
except:
continue
printGoodsList(infoList)
main()
8股票数据定向爬虫
具体可点击链接 https://blog.csdn.net/CJX_up/article/details/77912510
功能描述
目标:获取上交所和深交所所有股票的名称和交易信息
输出:保存到文件中
技术路线:requests-bs4-re
候选数据网站的选择
新浪股票:http://finance.sina.com.cn/stock/
百度股票:https://gupiao.baidu.com/stock/
选取原则:股票信息静态存在于HTML页面中,非JS代码生成,没有Robots协议限制。
选取方法:游览器F12,源代码查看等
程序的结构设计:
步骤1:从东方财富网获取股票列表
步骤2:根据股票列表逐个到百度股票获取个股信息
步骤3:将结果存储到文件
import requests
from bs4 import BeautifulSoup
import traceback
import re
def getHTMLText(url,code='utf-8'):
try:
r = requests.get(url,timeout = 30)
r.raise_for_status()
r.encoding = code
return r.text
except:
return ""
def getStockList(lst,stockURL):
html = getHTMLText(stockURL,'GB2312')
soup = BeautifulSoup(html,'html.parser')
a = soup.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):
count = 0
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':'bots-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')
count = count + 1
print('\r当前速度:{:.2f}%'.format(count*100/len(lst)),end='')
except:
count = count + 1
print('\r当前速度:{:.2f}%'.format(count*100/len(lst)),end='')
traceback.print_exc()
continue
return ""
def main():
stock_list_url = 'http://quote.eastmoney.com/stocklist'
stock_info_url = 'https://gupiao.baidu.com/stock/'
output_file = 'D://BaiduStockInfo.txt'
alist = []
getStockList(alist,stock_list_url)
getStockInfo(alist,stock_info_url,output_file)
main()
展示动态显示不换行进度条\r
count = count + 1
print('\r当前速度:{:.2f}%.format(count*100/len(lst)),end='')
9 Scrapy爬虫框架
详细内容请点击 https://blog.csdn.net/hxxjxw/article/details/90572756
scrapy 不是一个函数功能库,而是一个爬虫框架
爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。
爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫。
Engine:
不需要用户修改。控制所有模块之间的数据流,根据条件触发事件
Downloader:
根据请求下载网页,不需要用户进行修改
Scheduler:
对所有爬虫请求进行调度管理,不需要用户修改
Downloader Middleware:
目的:实施Engine、Scheduler和Downloader之间进行用户可配置的控制
功能:修改、丢弃、新增请求或响应
Spider:
解析Downloader返回的响应(Response)
产生爬取项(scraped item)
产生额外爬取请求(Request)
Item Pipelines:
以流水线的方式处理Spider产生的爬取项。
由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型。
可能操作包括:清理、检验和查重爬取项中的HTML数据、将数据存储到数据库。
Spider Middleware:
目的:对请求和爬取项的再处理
功能:修改、丢弃、新增请求或爬取项
详细介绍:
-
引擎(Engine) 用来处理整个系统的数据流处理, 触发事务(框架核心) -
调度器(Scheduler) 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址 -
下载器(Downloader) 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的 -
爬虫(Spiders) 爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面 -
项目管道(Pipeline) 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。 -
下载器中间件(Downloader Middlewares) 位于Scrapy引擎和下载器之间的框架,实施Engine、Scheduler和Downloader之间进行用户可配置的控制。修改、丢弃、新增请求或响应。 -
爬虫中间件(Spider Middlewares) 介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。 -
调度中间件(Scheduler Middewares) 介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。
requests vs scrapy
requests | Sceapy |
---|
页面级爬虫 | 网站级爬虫 | 功能库 | 框架 | 并发性考虑不足,性能较差 | 并发性好,性能较高 | 重点在于页面下载 | 重点在于爬虫结构 | 定制灵活 | 一般定制灵活,深度定制困难 | 上手十分简单 | 入门较难 |
Scrapy常用命令
命令 | 说明 | 格式 |
---|
startproject | 创建一个新工程 | scrapy startproject[dir] | genspider | 创建一个爬虫 | scrapy genspider[options] | settings | 获得爬虫配置信息 | scrapy setting[options] | crawl | 运行一个爬虫 | scrapy crawl | list | 列出工程中所有爬虫 | scrapy list | shell | 启动URL调试命令 | scrapy shell [url] |
为什么Scrapy采用命令行创建和运行爬虫?
命令行(不是图形界面)更容易自动化,适合脚本控制
本质上,Scrapy是给程序员使用的,功能(而不是界面)更重要
scrapy爬虫的基本使用
步骤一:采用命令行生成一个工程
输入scrapy startproject python123demo
生成的工程目录
python123demo/ :外层目录
? scrapy.cfg :部署scrapy爬虫的配置文件
? python123demo/ :Scrapy框架的用户自定义python代码
? —init—.py :初始化脚本
? items.py :Items代码模块(继承类)
? middleware.py :Middlewares代码模块(继承类)
? pipelines.py: Pipelines代码模板(继承类)
? settings.py :Scrapy的配置文件
? spiders/: Spiders代码模板目录(继承类)
? —init—.py: 初始文件,无需修改
? —pycache—/: 缓存目录无需修改
步骤二:在工程中产生一个Scrapy爬虫
打开命令行输入命令scrapy genspider demo python123.io,生成一个爬虫
demo.py文件
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
allowed_domains = ['python123.io']
start_urls = ['http://python123.io/']
def parse(self, response):
pass
步骤三:配置产生的spider爬虫
修改demo.py文件让它能够按照我们的要求访问链接,并爬取。
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('Saved file %s.' %name)
pass
步骤四:运行爬虫,获取网页。
命令行下执行scrapy crawl demo
yield关键字
yield----生成器
生成器是一个不断产生值的函数
包含yield语句的函数是一个生成器
生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值。
def gen(n):
for i in range(n):
yield i**2
for i in gen(5):
print(i,"",end="")
结果:0 1 4 9 16
10 scrapy爬虫的使用步骤
步骤1:创建一个工程和Spider模板
步骤2:编写spider
步骤3:编写Item Pipeline
步骤4:优化配置策略
Scrapy爬虫的数据类型
Request类
requests对象表示一个HTTP请求
属性或方法 | 说明 |
---|
.url | requests对应的请求URL地址 | .method | 对应的请求方法,‘GET’ 'POST’等 | .headers | 字典类型风格的请求头 | .body | 请求内容主体,字符串类型 | .meta | 用户添加的扩展信息,在scrapy内部模块间传递信息 | .copy() | 复制该请求 |
Response类
属性或方法 | 说明 |
---|
.url | response对应的url地址 | .status | http状态码,默认是200 | .hesders | response对应的头部信息 | .body | response对应得内容信息,字符串类型 | .flags | 一组标记 | .request | 产生resonse类型对应的request对象 | .copy() | 复制该响应 |
Item类
item对象表示从HTML页面中提取的信息内容
由spider生成,由item pipeline处理
item类似字典类型,可以按照字典类型操作
Scrapy爬虫支持多种HTML信息提取方法
Beautiful Soup |
---|
lxml | re | XPath Selector | CSS Selector |
css selector的基本使用
<html>.css('a::attr(href)').extract()
#a:标签名称 href:标签属性
实例:股票数据scrapy爬虫
步骤1:建立工程和spider模板
\>scrapy startproject BaiduStocks
\>cd BaiduStocks
\>scrapy genspider stocks baidu.com
进一步修改spider/stocks.py文件
步骤2:编写Spider
*配置stock.py文件
*修改对返回页面的处理
*修改对新增URL爬取请求的处理
spider
import scrapy
class StocksSpider(scrapy.Spider):
name = 'stocks'
allowed_domains = ['baidu.com']
start_urls = ['http://baidu.com/']
def parse(self, response):
pass
修改后
详情点击 https://www.cnblogs.com/douzujun/p/12249226.html
或者 https://www.jianshu.com/p/be3024c86c4c
esders | response对应的头部信息 | | .body | response对应得内容信息,字符串类型 | | .flags | 一组标记 | | .request | 产生resonse类型对应的request对象 | | .copy() | 复制该响应 |
Item类
item对象表示从HTML页面中提取的信息内容
由spider生成,由item pipeline处理
item类似字典类型,可以按照字典类型操作
Scrapy爬虫支持多种HTML信息提取方法
Beautiful Soup |
---|
lxml | re | XPath Selector | CSS Selector |
css selector的基本使用
<html>.css('a::attr(href)').extract()
#a:标签名称 href:标签属性
实例:股票数据scrapy爬虫
步骤1:建立工程和spider模板
\>scrapy startproject BaiduStocks
\>cd BaiduStocks
\>scrapy genspider stocks baidu.com
进一步修改spider/stocks.py文件
步骤2:编写Spider
*配置stock.py文件
*修改对返回页面的处理
*修改对新增URL爬取请求的处理
spider
import scrapy
class StocksSpider(scrapy.Spider):
name = 'stocks'
allowed_domains = ['baidu.com']
start_urls = ['http://baidu.com/']
def parse(self, response):
pass
修改后
详情点击 https://www.cnblogs.com/douzujun/p/12249226.html
或者 https://www.jianshu.com/p/be3024c86c4c
|