Python网络爬虫与信息提取

headpic

「初音ミクシンフォニー」BY:ののこ@ボーマスD79.80【Pixiv】

先是开始的一些废话

这个是去年寒假差不多的时候学习时记录的笔记,这两天翻出来炒一炒冷饭
Python网络爬虫与信息提取.MOOC.北京理工大学

requests库方法

1
pip install requests
方法 说明
requests.request() 构造一个请求,支撑以下各种方法
requests.get() 获取HTML网页的主要方法,对应于HTTP的GET
requests.head() 获取HTML网页头信息的方法,对应于HTTP的HEAD
requests.post() 向HTML网页提交POST请求的方法,对应于HTTP的POST
requests.put() 向HTML网页提交PUT请求的方法,对应于HTTP的PUT
requests.patch() 向HTML网页提交局部修改请求,对应于HTTP的PATCH
requests.delete() 向HTML网页提交删除请求,对应于HTTP的DELETE

Requests库的get方法

1
r = requests.get(url)

构造一个向服务器请求资源的Request对象
返回一个包含服务器资源的Response对象,包含爬虫返回的全部内容

完整使用方法:

1
requests.get(url, params=None, **kwargs)

url:拟获取页面的url链接
params:url中的额外参数,字典或字节流格式,可选

kwargs:12个控制访问的参数

Response对象的属性

属性 说明
r.status_code HTTP请求的返回状态,200表示连接成功
r.text HTTP响应内容的字符串形式,即url对应的页面内容
r.encoding 从HTTP header中猜测的相应内容编码方式
r.apparent_encoding 从内容分析出的响应内容编码方式(备选编码方式)
r.content HTTP相应内容的二进制形式

Requests库的异常

异常 说明
requests.ConnectionError 网络连接错误异常,如DNS查询失败、拒绝连接等
requests.HTTPError HTTP错误异常
requests.URLRequired URL缺失异常
requests.TooManyRedirects 超过最大重定向次数,产生重定向异常
requests.ConnectTimeout 连接远程服务器超时异常
requests.Timeout 请求URL超时,产生超时异常
r.raise_for_status()
如果不是200,产生异常requests.HTTPError

抓取网页的通用代码框架

1
2
3
4
5
6
7
8
9
10
import requests

def getHTMLText(url):
try:
r = requests.get(rul, timeout=30)
r.raise_for_status() #如果状态不是200,引发HTTPError异常
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"

HTTP协议

url格式  http://host[:port][path]

host:合法的Internet主机域名或IP地址
port:端口号,缺省端口为80
path:请求资源的路径

HTTP协议对资源的操作

方法 说明
GET 请求获取URL位置的资源
HEAD 请求获取URL位置资源的响应消息报告,即获得该资源的头部信息
POST 请求向URL位置的资源后附加新的数据
PUT 请求向URL位置存储一个资源,覆盖原URL位置的资源
PATCH 请求局部更新URL位置的资源,即改变该处资源的部分内容
DELETE 请i去删除URL位置存储的资源

HTTP协议与Requests库

HTTP协议 Requests库方法 功能一致性
GET requests.get() 一致
HEAD requests.head() 一致
POST requests.post() 一致
PUT requests.put() 一致
PATCH requests.patch() 一致
DELETE requests.delete() 一致

Requests库的head()方法

1
2
3
r = requests.head('http://httpbin.org/get')
r.headers
r.text

Requests库的post()方法

1
2
3
4
5
6
7
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post('http://httpbin.org/post', data = payload)
print(r.text)
# 向URL POST一个字典,自动编码为form(表单)
r = requests.post('http://httpbin.org/post', data = 'ABC')
print(r.text)
# 向URL POST一个字符串,自动编码为data

Requests库的put()方法

1
2
3
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.put('http://httpbin.org/put', data = payload)
print(r.text)

Requests库主要方法解析

1
requests.request(method, url, **kwargs)

method:请求方式,对应get/put/post等7种
url:拟获取页面的url链接

**kwargs:控制访问的参数,共13个

methond:请求方式

1
2
3
4
5
6
7
requests.request('GET', url, **kwargs)
requests.request('HEAD', url, **kwargs)
requests.request('POST', url, **kwargs)
requests.request('PUT', url, **kwargs)
requests.request('PATCH', url, **kwargs)
requests.request('delete', url, **kwargs)
requests.request('OPTIONS', url, **kwargs)

**kwargs:控制访问参数,均为可选项

params:字典或字节序列,作为参数增加到url中
data:字典字节序列或文件对象,作为Request的内容
json:JSON格式的数据,作为Request的内容
headers:字典,HTTP定制头
cookies:字典或CookieJar,Request中的cookie
auth:元祖,支持HTTP认证功能
files:字典类型,传输文件
timeout:设定超时时间,秒为单位
proxies:字典类型,设定访问代理服务器,可以增加登陆认证
allow_redirects:True/False,默认为True,重定向开关
stream:True/False,默认为True,获取内容立即下载开关
verify:True/False,默认为True,认证SSL证书开关
cert:本地SSL证书路径

其它6个主要函数

1
requests.get(rul, params = None, **kwargs)

url:拟获取页面的url链接
params:url中的额外参数,字典或字节流格式,可选

**kwargs:12个控制访问参数

1
requests.head(url, **kwargs)

url:拟获取页面的url连接

**kwargs:13个控制访问的参数

1
requests.post(url, data=None, json=None, **kwargs)

url:拟更新页面的url链接
data:字典、字节序列或文件,Request的内容
json:JSON格式的数据,Request的内容

**kwargs:11个控制访问的参数

1
requests.put(url, data=None, **kwargs)

url:拟更新页面的rul链接
data:字典、字节序列或文章,Request的内容

**kwargs:12个控制访问参数

1
requests.patch(url, data=None, **kwargs)

url:拟更新页面的url链接
data:字典、字节序列或文件,Request的内容

**kwargs:12个控制访问的参数

1
requests.delete(url, **kwargs)

url:拟删除页面的url链接

**kwargs:13个控制访问的参数

Robots协议

Robots Exclusion Standard 网络爬虫排除标准
# 注释,*代表所有,/代表目录

作用:网站告知网络爬虫哪些页面可以抓取,哪些不行
形式:在网站根目录下的robots.txt文件

Robots协议的使用

网络爬虫:自动或人工识别robots.txt,再进行内容爬取
约束性:Robots协议是建议但非约束性,网络爬虫可以不遵守,但存在法律风险

实例1:京东商品页面的爬取

http://item.jd.com/2967929.html

1
2
3
4
5
6
7
8
9
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)
except:
print("爬取失败")

实例2:亚马逊商品页面爬取

https://www.amazon.cn/gp/product/B01M8L5Z3Y

1
2
3
4
5
6
7
8
9
10
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)
except:
print("爬取失败")

实例3:百度/360搜索关键词提交

搜索关键词接口

百度的关键词接口:http://www.baidu.com/s?wd=keyword
360的关键词接口:http://www.so.com/s?q=keyword

1
2
3
4
5
6
7
8
9
10
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("爬取失败")

实例4:网络图片的爬取和存储

网络图片链接的格式:http://www.example.com/picture.jpg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
import os
url = "http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg"
root = "G:/Code/python/mooc爬虫/"
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)
print("文件保存成功")
else:
print("文件已存在")
except:
print("爬取失败")

实例5:IP地址归属地自动查询

api:http://m.ip138.com/ip.asp?ip=ipaddress

1
2
3
4
5
6
7
8
9
import requests
url = "http://m.ip138.com/ip.asp?ip="
try:
r = requests.get(url+'202.204.80.112')
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text)
except:
print("爬取失败")

Beautiful Soup 库

Beautiful Soup 库是解析、遍历、维护“标签树”的功能库

1
pip install beautifulsoup4

Beautiful Soup 库的引用

1
from bs4 import BeautifulSoup

Beautiful Soup 库解析器

解析器 使用方法 条件
bs4的HTML解析器 BeautifulSoup(mk,’html.parser’) 安装bs4库
xlml的HTML解析器 BeautifulSoup(mk,’lxml’) pip install lxml
lxml的XML解析器 BeautifulSoup(mk,’xml’) pip install lxml
html5lib的解析器 BeautifulSoup(mk,’html5lib’) pip install html5lib

Beautiful Soup 类的基本元素

基本元素 说明
Tag 标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾
Name 标签的名字,\

…\

的名字是‘p’,格式:\.name
Attributes 标签的属性,字典形式组织,格式:\.attrs
NavigableString 标签内非属性字符串,<>…</>中字符串,格式:\.string
Comment 标签内字符串的注释部分,一种特殊的Comment类型

基于bs4库的HTML内容遍历方法

1
2
3
4
5
6
import requests
from bs4 import BeautifulSoup

r = requests.get("http://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")

标签树的下行遍历

属性 说明
.contents 子节点的列表,将\所有子节点存入列表
.children 子节点的迭代类型,与.contents类似,用于循环遍历子节点
.descendants 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历

标签树的上行遍历

属性 说明
.parent 节点的父标签
.parents 节点先辈标签的迭代类型,用于循环遍历先辈节点

标签树的平行遍历

属性 说明
.next_sibling 返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling 返回按照HTML文本顺序的上一个平行节点标签
.next_siblings 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

基于bs4库的HTML内容查找方法

1
<>.find_all(name, attrs, recursive, string, **kwargs)

返回一个列表类型存储查找的结果

name:对标签名称的检索字符串
attrs:对标签属性值的检索字符串,可标注属性检索
recursive:是否对子孙全部搜索,默认True
string:<>…</>中字符串区域的检索字符串

扩展方法

方法 说明
<>.find() 搜索且只返回一个结果,字符串类型,同.find_all()参数
<>.find_parents() 在先辈节点中搜索,返回列表类型,同.find_all()参数
<>.find_parent() 在先辈节点中返回一个结果,字符串类型,同.find()参数
<>.find_next_siblings() 在后续平行节点中搜索,返货列表类型,同.find_all()参数
<>.find_next_sibling() 在后续平行节点中返回一个结果,字符串类型,同.find()参数
<>.find_prrevious_siblings() 在前续平行节点中,返回一个列表类型,同.find_all()参数
<>.find_previous_sibling() 在前序平行节点中返回一个结果,字符串类型,同.find()参数

实例:中国大学排名定向爬虫

http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html

功能描述

  • 输入:大学排名URL链接
  • 输出:大学排名信息的屏幕输出(排名,大学名称,总分)
  • 技术线路:requests-bs4
  • 定向爬虫:仅对输入URL进行爬取,不扩展爬取

程序的结构设计

  • 步骤1:从网络上获取大学排名内容getHTMLText()
  • 步骤2:提取网页内容中信息到合适的数据结构fillUnivList()
  • 步骤3:利用数据结构展示并输出结果printUnivList()

中文对齐问题

<填充> <对齐> <宽度> <.精度> <类型>
引导符号 用于填充的单个字符 <左对齐
^右对齐
>居中对齐
槽的设定输出宽度 数字的千位分隔符适用于整数和浮点数 浮点数小鼠部分的精读或字符串的最大输出长度 整数类型b,c,d,o,x,X
浮点数类型e,E,f,%
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import requests
from bs4 import BeautifulSoup
import bs4

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.find_all('td')
ulist.append([tds[0].string, tds[1].string, tds[2].string])

def printUnivList(ulist, num):
tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
print(tplt.format("排名", "学校名称", "省市", chr(12288))) # 12288 是中文空格的utf-8编码
for i in range(num):
u = ulist[i]
print(tplt.format(u[0], u[1], u[2], chr(12288)))

def main():
uinfo = []
url = "http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html"
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 20 univs

if __name__ == "__main__":
main()

正则表达式RE

regular expression

  • 通用的字符串表达框架
  • 简介表达一组字符串的表达式
  • 针对字符串表达“简洁”和“特征”思想的工具
  • 判断某字符串的特征归属

正则表达式在文本处理中十分常用

  • 表达文本类型的特征(病毒、入侵等)
  • 同时查找或替换一组字符串
  • 匹配字符串的全部或部分

正则表达式的使用

  • 编译:将符合正则表达式语法的字符串转换成正则表达式特征

正则表达式的常用操作符

操作符 说明 实例
. 表示任何单个字符
[] 字符集,对单个字符给出取值范围 [abc]表示a、b、c,[a-z]表示a到z单个字符
[^ ] 非字符集,对单个字符给出排除范围 [^abc]表示非a或非b或非c的单个字符
* 前一个字符0次或无限次扩展 abc* 表示ab、abc、abcc、abccc等
+ 前一个字符1次或无限次扩展 abc+ 表示abc、abcc、abccc等
? 前一个字符0次或1次扩展 abc? 表示ab、abc
\ 左右表达式任意一个 abc\ def 表示abc、def
{m} 扩展前一个字符m次 ab{2}表示abbc
{m, n} 扩展前一个字符m至n次(含n) ab{1, 2}c表示abc、abbc
^ 匹配字符串开头 ^abc表示abc且在一个字符串开头
$ 匹配字符串结尾 abc$表示abc且在一个字符串的结尾
() 分组标记,内部只能使用 \ 操作符 (abc)表示abc,(abc\ def)表示abc、def
\d 数字,等价于[0-9]
\w 单词字符,等价于[A-Za-z0-9_]

IP地址形式的正则表达式

1
(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])

RE库的基本使用

RE库是python的标准库,主要用于字符串匹配

1
import re

  • raw string 类型(原生字符串类型)

    re 库采用 raw string 类型表示正则表达式,表示为:r’text’
    例如
    r’[1-9]\d{5}
    r’\d{3}-\d{8}|\d{4}-\d{7}’
    raw string 是不包含转义符的字符串

  • string 类型,更繁琐

    ‘[1-9]\\d{5}’
    ‘\\d{3}-\\d{8}|\\d{4}-\\d{7}’

Re库主要功能函数

函数 说明
re.search() 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match() 从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall() 搜索字符串,以列表类型返回全部能匹配的字串
re.split() 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.finditer() 搜索字符串,返回一个匹配结果的迭代匹配类型,每个迭代元素是match对象
re.sub() 在一个字符串中替换所有匹配正则表达式的字串,返回替换后的字符串
1
re.search(pattern, string, flags=0)

pattern:正则表达式的字符串或原生字符串表示
string:待匹配字符串
flags:正则表达式使用时的控制标记

常用标记 说明
re.I re.IGNORECASE 忽略正则表达式的大小写,[A-Z]能够匹配小写字符串
re.M re.MULTILINE 正则表达式中的^操作符能够将给定字符串的每行当作匹配开始
re.S re.DOTALL 正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符
1
re.match(pattern, string, flags=0)

pattern:正则表达式的字符串或原生字符串表示
string:待匹配字符串
flags:正则表达式使用时的控制标记

1
re.findall(pattern, string, flags=0)

pattern:正则表达式的字符串或原生字符串表示
string:待匹配字符串
flags:正则表达式使用时的控制标记

1
re.split(pattern, string, maxsplit=0, flags=0)

pattern:正则表达式的字符串或原生字符串表示
string:待匹配字符串
maxsplit:最大分割数,剩余部分作为最后一个元素输出
flags:正则表达式使用时的控制标记

1
re.finditer(pattern, string, flags=0)

pattern:正则表达式的字符串或原生字符串表示
string:待匹配字符串
flags:正则表达式使用时的控制标记

1
re.sub(pattern, repl, string, count=0, flags=0)

pattern:正则表达式的字符串或原生字符串表示
repl:替换匹配字符串的字符串
string:待匹配字符串
count:匹配的最大替换次数
flags:正则表达式使用时的控制标记

两种正则表达式的使用方式

1
2
3
4
5
6
# 函数式用法:一次性操作
rst = re.search(r'[1-9]\d{5}', 'BIT 100081)

# 面向对象用法:编译后的多次操作
pat = re.compile(r'[1-9]\d{5}')
rst = pat.search('BIT 100081')
1
re.cimpile(pattern, flags=0)

将正则表达式的字符串形式编译成正则表达式对象
pattern:正则表达式的字符串或原生字符串表示
flags:正则表达式使用时的控制标记

Re库的另一种等价用法

函数 说明
regex.search() 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match() 从一个字符串的开始位置起匹配正则表达式,返回match对象
regex.findall() 搜索字符串,以列表类型返回全部能匹配的字串
regex.split() 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
regex.finditer() 搜索字符串,返回一个匹配结果的迭代匹配类型,每个迭代元素是match对象
regex.sub() 在一个字符串中替换所有匹配正则表达式的字串,返回替换后的字符串

调用以上方法时,只需要把原方法中的pattern参数去掉

Re库的match对象

Match对象的属性

属性 说明
.string 带匹配的文本
.re 匹配时使用的pattern对象(正则表达式)
.pos 正则表达式搜索文本的开始位置
.endpos 正则表达式搜索文本的结束位置

Match对象的方法

方法 说明
.group(0) 获得匹配后的字符串
.start() 匹配字符串在原始字符串的开始位置
.end() 匹配字符串在原始字符串的结束位置
.span() 返回(.start(),.end())

更多group(n)方法请阅读相关文档

Re库的贪婪匹配和最小匹配

1
2
match = re.search(r'PY.*N', 'PYANBCNDN')
match.group(0)

贪婪匹配

Re库默认采用贪婪匹配,即输出匹配最长的字串

最小匹配

1
2
match = re.search(r'PY.*?N', 'PYANBCNDN')
match.group(0)

最小匹配操作符

操作符 说明
*? 前一个字符0次或无限次扩展,最小匹配
+? 前一个字符1次或无限次扩展,最小匹配
?? 前一个字符0次或1次扩展,最小匹配
{m, n}? 扩展前一个字符m至n次(含n),最小匹配

实例:淘宝比价定向爬虫

起始页https://s.taobao.com/search?q=书包&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8
第二页https://s.taobao.com/search?q=书包&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&s=44
第三页https://s.taobao.com/search?q=书包&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&s=88

功能描述

  • 目标:获取淘宝搜索页面的信息,提取其中的商品名称和价格
  • 理解:
    • 淘宝的搜索接口
    • 翻页的处理
  • 技术路线:requests-re

程序的结构设计

  • 步骤1:提交商品搜索请求,循环获取页面
  • 步骤2:对于每个页面,提取商品名称和价格信息
  • 步骤3:将信息输出到屏幕上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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=书包&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8' + goods
infoList = []
for i in range(depth):
try:
url = start_url + '&s=' + str(44 * i)
html = getHTMLText(url)
parsePage(infoList, html)
except:
print("exception")
printGoodsList(infoList)

if __name__ == "__main__":
main()

实例:股票数据定向爬虫

新浪股票:http://finance.sina.com.cn/stock/
百度股票:http://gupiao.baidu.com/stock
功能描述

  • 目标:获取上交所和深交所所有股票的名称和交易信息
  • 输出:保存到文件中
  • 技术线路:requests-bs4-re

候选数据网站的选择:

  • 选取原则:股票信息静态存在于HTML页面中,非js代码生成,没有Robots协议限制
  • 选取方法:浏览器F12,源代码查看等
  • 选取心态:不要纠结于某个网站,多找信息源尝试

程序结构设计

  • 步骤1:从东方财富网获取股票列表
  • 步骤2:根据股票列表逐个到百度股票获取个股信息
  • 步骤3:将结果存储到文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    import requests
    import re
    from bs4 import BeautifulSoup
    import traceback

    def getHTMLText(url, code='utf-8'):
    try:
    r = requests.get(url)
    r.raise_for_status()
    r.encoding = code
    return r.text
    except:
    return""

    def getStockList(lst, stockURL):
    html = getHTMLText(stockURL)
    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':'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')
    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="")
    continue

    def main():
    stock_list_url = "http://quote.eastmoney.com/stocklist.html"
    stock_info_url = "http://gupiao.baidu.com/stock/"
    output_file = "G:/Code/python/mooc爬虫/BaiduStockInfo.txt"
    slist = []
    getStockList(slist, stock_list_url)
    getStockInfo(slist, stock_info_url, output_file)

    main()

Scrapy爬虫框架

1
pip install scrapy

爬虫框架

  • 爬虫框架是实现爬虫功能的一个软件结构和功能组件集合
  • 爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫

    Scrapy爬虫框架结构

    “5+2”结构
  • ENGINE
  • SCHEDULER
  • ITEM PIPELINES
  • SPIDERS
  • DOWNLOADER

Scrapy爬虫框架结构
Scrapy爬虫框架结构1
Scrapy爬虫框架结构2

Scrapy爬虫框架解析

Engine

  • 控制所有模块之间的数据流
  • 根据条件触发事件

    Downloader

  • 根据请求下载网页

    Scheduler

  • 对所有请求进行调度管理

    Downloader Middleware

  • 目的:试试Engine、Scheduler和Downloader之间进行用户可配置的控制
  • 功能:修改、丢弃、新增请求或响应

    Spider

  • 解析Downloader返回的响应(Response)
  • 产生爬取项(scraped item)
  • 产生额外的爬取请求(Request)

    Item Pipelines

  • 以流水线方式处理Spider产生的爬取项
  • 由一组操作顺序组成,类似流水线,每个操作是一个 Item Pipeline 类型
  • 可能操作包括:清理、检验和查重爬取项中的HTML数据、将数据存储到数据库

    Spider Middleware

  • 目的:对请求和爬取项的再处理
  • 功能:修改、丢弃、新增请求或爬取项

    requests vs. Scrapy

    相同点

  • 两者都可以进行页面请求和爬取,Python爬虫的两个重要技术线路
  • 两者可用性都好,文档丰富,入门简单
  • 两者都没有处理js、提交表单、应对验证码等功能(可扩展)

    不同点

    requests|Scrapy
    —-|—-
    页面级爬虫|网站级爬虫
    功能库|框架
    并发性考虑不足|并发性好,性能较高
    重点在于页面下载|重点在于爬虫结构
    定制灵活|一般定制灵活,深度定制困难
    上手十分简单|上手稍难

    Scrapy爬虫的常用命令

    Scrapy是为持续运行设计的专业爬虫框架,提供操作的Scrapy命令行
1
scrapy <command> [options] [args]

Scrapy常用命令

命令 说明 格式
startproject 创建一个新工程 scrapy startproject [dir]
genspider 创建一个爬虫 scrapy genspider [options] [domain]
settings 获得爬虫配置信息 scrapy settings [options]
crawl 运行一个爬虫 scrapy crawl
list 列出工程中所有爬虫 scrapy list
shell 启动URL调试命令行 scrapy shell [url]

Scrapy爬虫基本使用

待续

谢谢观众姥爷们的支持鼓励qwqありがとうございます~