学习python的视频https://www.bilibili.com/video/av69060979?p=1
以爬虫视角,看待网络内容(来源:学习强国平台,北京理工大学学习视频 北京理工大学崇天)
requests.request() | requests.put() |
---|---|
requests.get() | requests.patch() |
requests.head() | requests.delete() |
requests.post() |
try:
r = requests.get(url, timeout=30)
r.raise_for_status()#返回200表示访问成功
r.enconding = r.apparent_encoding
return r.text
except:
return "产生异常"
#网络连接有风险,异常处理很重要
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("爬取失败")
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("爬取失败")
提供关键词,得到搜索结果
百度的关键词接口: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("爬取失败")
网络图片链接的格式:http://www.example.com/picture.jpg
http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg
import requests
import os#引入os库
url = "http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg"
root = D://pics//"#文件的目录
path = root +url.split('/')[-1]#文件的目录加上jpg文件最后一部分,文件名称和网络图片名称相同
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:#wb图片为二进制文件
f.write(r.content)
f.close()
print("文件保存成功")
else:
print("文件已存在")
except:
print("爬取失败")
类似的url,网上的视频、图片、动画、flash都可以用这个框架爬取
比如某一个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')#北京理工大学教育网的IP地址
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[-500])
except:
print("爬取失败")
小规模数据量较小,爬取数据不敏感, Requests库 | 中规模,数据规模较大,爬取速度敏感 Scrapy库 | 大规模,搜索引擎,爬取速度关键 定制开发 |
---|---|---|
爬取网页,玩转网页 | 爬取网站,爬取系列网站 | 爬取全网 |
骚扰问题、法律风险、泄露隐私
*来源审查:判断User-Agent进行限制
*发布公告:Robots协议
robots.txt(符合Robots 协议 (又称:爬虫协议、机器人协议等,全称:“网络爬虫排除标准”))是爬虫访问目标网站时查看的第一个文件,他会限定网络爬虫的访问范围。如果文件存在,则爬虫会按照该文件的内容确定访问的范围,否则,爬虫能访问所有没有密码保护的页面。
#注释:*代表所有,/代表根目录
User-Agent: *
Disallow: /
记录 | 作用 |
---|---|
User-Agent | 描述搜索引擎(爬虫)的名字,至少一个。若其值为“ * ”,则表示该协议对任何搜索引擎都有效,且这样的记录只有一条 |
Disallow | 描述不希望被访问的URL,可以是完整路径,也可以是部分路径。任何一条该类记录为空,说明该网站的所有部分都可访问。在robots.txt文件中,至少有一条该类记录 |
Allow | 描述希望被访问的URL,与 Disallow 类似。一个网站的所有 URL 默认Allow,所以通常与 Disallow 搭配使用,实现允许访问已备份网页的同时,禁止访问其他所有 URL 的功能 |
类人行为可以不参考Robots协议
页面网址:https://python123.io/ws/demo.html
from bs4 import BeautifulSoup
soup = BeautifulSoup('data
'
,'html.parser')
#第一个参数表述,解析的东西,第二个参数表示传递html解析器
解析、遍历、维护“标签树”的功能库
将标签树转换为BeautifulSoup类
解析器 | 使用方法 | 条件 |
---|---|---|
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 |
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
print(soup.title)
tag = soup.a#定义一个标签获取a标签的内容
print(tag)
#获取标签名字
print(soup.a.name)
print(soup.a.parent.name)#同过标签.name的方式获取其名字
#获取标签的属性
tag = soup.a
print(tag.atts)
print(tag.attrs['class'])#获得a标签class属性的值
print(tag.attrs['href'])#获得a标签链接属性的值
#获取标签之间的字符串信息
print(soup.a.string)
print(soup.p.string)
#获取注释
newsoup = BeautifulSoup("")
print(newsoup.p.string)
属性 | 说明 |
---|---|
.content | 子节点列表,将标签所有儿子节点存入列表 |
.children | 子节点的迭代类型,与.content类似,用于循环遍历儿子节点 |
.descendants | 子孙节点的迭代类型,包含所有的子孙节点 |
for chlid in soup.body.children:#遍历儿子节点
print(child)
for child in soup.body.children:#遍历子孙节点
print(child)
属性 | 说明 |
---|---|
.parent | 节点的父亲标签 |
.parents | 节点先辈标签的迭代类型,用于循环遍历先辈节点 |
属性 | 说明 |
---|---|
.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)
如何让HTML内容更加友好的显示?
通常BeautifulSoup解析得到的Beautifulsoup对象格式较杂乱,可在输出时使用 **prettify() **方法对BeautifulSoup对象进行美化(为标签和内容添加换行符和缩进,以便于更友好直观地显示HTML内容),示例如下:
print(soup.prettify())
XML尖括号、标签表达信息的标记形式(html属于XML)
最早的标记语言,相当繁琐
Internet上的信息交互与传递
JSON 有类型的键值对标记
信息有类型,适合程序处理,较XML简洁
移动云端和节点的信息通信,无注释
无类型的键值对标记
信息无类型,文本信息比例最高,可读性非常好
各类系统的配置文件,有注释且移动
解析格式 XML JSON YAML?
需要标记解析器 例如:bs4
优点:信息解析准确
缺点:提取过程繁琐,速度慢
搜索
对信息文本查找函数即可
优点:提取过程简洁,速度较快
缺点:提取结果准确性与信息内容相关
如何提取,融合方法一方法二
思路:1)搜索到所有的标签
2)解析标签格式,提取href后的链接内容·。
from bs4 import BeaytifulSoup
soup = BeautifulSoup(demo,"html.parser")
for link in soup.find_all('a'):
print(link.get('href'))
#http://www.icourse163.org/course/BIT-268001
#http://www.icourse163.org/course/BIT-1001870001
网页中的信息都存在于网页的文本或者各种不同标签的属性值,为获得这些有用的网页信息,可通过一些查找方法获取文本或标签属性。bs4 库内置一些查找方法,其中最常用的两个方法功能如下:
方法 | 功能 |
---|---|
find() | 查找符合查询条件的第一个标签节点 |
find_all() | 查找所有符合查询条件的标签节点,并返回一个列表 |
这两个方法的参数相同,以find_all() 为例,介绍该方法中参数的作用,find_all() 定义如下:
find_all(self,name=Nobe,attrs={key:value},recursive=True,text=None,limit=None,**kwargs)
上述方法中的一些重要参数含义如下:
查找所有名字为name的标签,但**‘name=’**字符串会被忽略.以下是name参数的几种情况:
传入字符串
在搜索的方法中传入一个字符串,BeautifulSoup 对象会查找与字符串完全匹配的内容.例如:
soup.find_all('b') #查找文档中所有的标签
```###### 1.2 传入正则表达式
如果传入一个正则表达式,那么BeautifulSoup对象会通过re模块的match()函数进行匹配.例如:
```python
soup.find_all(re.compile("^b"))#使用正则表达式匹配所有以字母b开头的标签
```###### 1.3 传入列表
如果传入一个列表,那么BeautifulSoup对象将会与列表中任意元素匹配的内容返回.例如:
soup.find_all([“a”,“b”]) #返回文档中所有标签和标签
如果某个指定名字的参数不是搜索方法中内置的参数名,那么在进行搜索时,会把该参数当作指定名字的标签中的属性搜索.例如:
```python
soup.find_all(id='link2')#在find_all()方法中传入名称为id,值为link2的参数,此时BeautifulSoup对象会搜索每个标签的属性
若传入的参数属于Python保留字(如: class),可以在保留字后添加一条下划短线.例如:
soup.find_all(class_='sister')
对标签属性值的检索字符串,可标注属性检索
soup.find_all('p','course')#查找p标签中包含course字符串的信息
soup.find_all(id='link1')#对属性做相关的约定,查找属性为link1的元素
若传入多个指定名字的参数,则可同时过滤出标签中的多个属性.例如:
import re #正则表达式库
soup.find_all(href=re.compile("elsie"),id='link1')
是否对子孙全部检索,默认True
标签之间的内容
soup.find_all(string = "Basic Python")#精确的输入字符串进行检索
#输出['Basic Python']
#如果只希望用python检索到更多的信息,则引入re正则表达式库
import re
soup.find_all(string = re.compile("python"))
#输出['This is a python demo page', 'The demo python introduces several python courses.']
(…)等价于.find_all(…)
soup(…)等价于soup.find_all(…)
功能描述
输入:大学排名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)#20 univs
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:#tr没一所大学对应的信息
if isinstance(tr,bs4.element.Tag):#检测tr标签类型,过滤掉非标签类型
tds = tr('td')#找到td标签
ulist.append([tds[0].string,tds[1].string,tds[3].string])
#把我们需要的td标签加到列表中
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))
正确输出
正则表达式 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]** 这个范围不包括全角(中文)标点,但大多数情况是可以使用的。
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_] |
正则表达式 | 对应字符串 |
---|---|
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’ |
匹配模式常用在编译正则表达式时,作用涉及 区分大小写、忽略非法字符等。
正则表达式的模式时可以同时使用多个的,在Python里使用 | 同时添加多个模式
匹配模式flages | 说明 |
---|---|
re.I | 忽略大小写 |
re.L | 字符集本地化,该功能是为了支持多语言版本的字符集使用环境。比如‘\w’在英文环境下,代表匹配字母数字,但在法语环境下,缺省设置导致不能匹配法语字符,加上该选项就可匹配。但该选项仍对中文不友好,不能匹配中文字符。 |
re.M | 多行模式,改变 ^ 和 $ 的行为 |
re.S | 点任意匹配模式,此模式下,‘.’的匹配不受限制,可匹配包括换行符在内的任何字符 |
re.X | 冗余模式(详细模式),此模式忽略正则表达式中的空白字符和#的注释(注释与表达式可多行书写) |
re.U | 使用\w,\W,\b,\B 这些元字符时将按照Unicode定义的属性 |
函数 | 用法详解 |
---|---|
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
rst = re.search(r'[1-9]\d{5},'BIT 10086')
#函数式用法:一次性操作
#面向对象用法:编译后的多次操作。好处,多次使用可以加快程序运行
#regex = re.compile(pattern,flags=0)将正则表达式字符串形式编译成正则表达式对象,
regex = re.complie(r'[1-9]\d{5}')
rst = regex.search('BIT 10081')
属性 | 说明 |
---|---|
.string | 待匹配的文本 |
.re | 匹配时使用的pattern对象(正则表达式) |
.pos | 正则表达式搜索文本的开始位置 |
.endpos | 正则表达式搜索文本的结束位置 |
方法 | 说明 |
---|---|
.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)#返回的是第一次匹配的结果,finditer()返回全部
'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),最小匹配 |
方法 | 说明 |
---|---|
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
功能描述
目标:获取淘宝搜索页面的信息,提取其中的商品,提取其中的商品名称和价格。
理解:淘宝的搜索接口
翻页的处理
技术路线: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])#eval函数将所获得字符中的双引号和单引号去掉
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()
具体可点击链接 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])#以s开头中间是h或z字符,后面有6个数
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]})#使用split分割
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()
count = count + 1
print('\r当前速度:{:.2f}%.format(count*100/len(lst)),end='')
详细内容请点击 https://blog.csdn.net/hxxjxw/article/details/90572756
scrapy 不是一个函数功能库,而是一个爬虫框架
爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。
爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫。
不需要用户修改。控制所有模块之间的数据流,根据条件触发事件
根据请求下载网页,不需要用户进行修改
对所有爬虫请求进行调度管理,不需要用户修改
目的:实施Engine、Scheduler和Downloader之间进行用户可配置的控制
功能:修改、丢弃、新增请求或响应
解析Downloader返回的响应(Response)
产生爬取项(scraped item)
产生额外爬取请求(Request)
以流水线的方式处理Spider产生的爬取项。
由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型。
可能操作包括:清理、检验和查重爬取项中的HTML数据、将数据存储到数据库。
目的:对请求和爬取项的再处理
功能:修改、丢弃、新增请求或爬取项
详细介绍:
引擎(Engine)
用来处理整个系统的数据流处理, 触发事务(框架核心)
调度器(Scheduler)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
下载器(Downloader)
用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的
爬虫(Spiders)
爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
项目管道(Pipeline)
负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
下载器中间件(Downloader Middlewares)
位于Scrapy引擎和下载器之间的框架,实施Engine、Scheduler和Downloader之间进行用户可配置的控制。修改、丢弃、新增请求或响应。
爬虫中间件(Spider Middlewares)
介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。
调度中间件(Scheduler Middewares)
介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。
requests | Sceapy |
---|---|
页面级爬虫 | 网站级爬虫 |
功能库 | 框架 |
并发性考虑不足,性能较差 | 并发性好,性能较高 |
重点在于页面下载 | 重点在于爬虫结构 |
定制灵活 | 一般定制灵活,深度定制困难 |
上手十分简单 | 入门较难 |
命令 | 说明 | 格式 |
---|---|---|
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 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 genspider demo python123.io,生成一个爬虫
demo.py文件
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'#当前爬虫名字叫demo
allowed_domains = ['python123.io']#只能爬取这个域名以下的相关链接
start_urls = ['http://python123.io/']#Scrapy框架所能爬取的初始页面
def parse(self, response):
pass
# parse()用于处理响应,解析内容成字典,发现新的URL爬取请求。
修改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语句),函数被冻结,被唤醒后再产生一个值。
def gen(n):
for i in range(n):
yield i**2
for i in gen(5):
print(i,"",end="")
结果:0 1 4 9 16
步骤1:创建一个工程和Spider模板
步骤2:编写spider
步骤3:编写Item Pipeline
步骤4:优化配置策略
requests对象表示一个HTTP请求
属性或方法 | 说明 |
---|---|
.url | requests对应的请求URL地址 |
.method | 对应的请求方法,‘GET’ 'POST’等 |
.headers | 字典类型风格的请求头 |
.body | 请求内容主体,字符串类型 |
.meta | 用户添加的扩展信息,在scrapy内部模块间传递信息 |
.copy() | 复制该请求 |
属性或方法 | 说明 |
---|---|
.url | response对应的url地址 |
.status | http状态码,默认是200 |
.hesders | response对应的头部信息 |
.body | response对应得内容信息,字符串类型 |
.flags | 一组标记 |
.request | 产生resonse类型对应的request对象 |
.copy() | 复制该响应 |
item对象表示从HTML页面中提取的信息内容
由spider生成,由item pipeline处理
item类似字典类型,可以按照字典类型操作
Beautiful Soup |
---|
lxml |
re |
XPath Selector |
CSS Selector |
css selector的基本使用
.css('a::attr(href)').extract()
#a:标签名称 href:标签属性
步骤1:建立工程和spider模板
\>scrapy startproject BaiduStocks
\>cd BaiduStocks
\>scrapy genspider stocks baidu.com
进一步修改spider/stocks.py文件
步骤2:编写Spider
*配置stock.py文件
*修改对返回页面的处理
*修改对新增URL爬取请求的处理
spider
# -*- coding: utf-8 -*-
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对象表示从HTML页面中提取的信息内容
由spider生成,由item pipeline处理
item类似字典类型,可以按照字典类型操作
Beautiful Soup |
---|
lxml |
re |
XPath Selector |
CSS Selector |
css selector的基本使用
.css('a::attr(href)').extract()
#a:标签名称 href:标签属性
步骤1:建立工程和spider模板
\>scrapy startproject BaiduStocks
\>cd BaiduStocks
\>scrapy genspider stocks baidu.com
进一步修改spider/stocks.py文件
步骤2:编写Spider
*配置stock.py文件
*修改对返回页面的处理
*修改对新增URL爬取请求的处理
spider
# -*- coding: utf-8 -*-
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