Python爬虫笔记
Resquest库
r = requests.get(url, params=None,**kwargs)
requests是一个response对象
主要方法:
requests.request() 构造一个请求,支撑一下各方法
requests.get() 获取网页
requests.head () 获取头信息
requests.post() 提交POST请求
requests.put() 提交PUT请求
requests.patch() 提交局部修改请求
requests.delete() 提交删除请求
response对象的属性:
r.status_code HTTP请求返回状态,200成功,404失败
r.text HTTP响应内容的字符串形式,即url对应的页面内容
r.encoding 从HTTPheader中猜测的响应内容编码方式
r.apparent_encoding从内容中分析的响应内容编码方式,备选
r.contemt HTTP响应的二进制形式
错误处理:
requests.ConnectionError 网络连接异常 DNA异常拒绝连接
requests.HTTPError HTTP错误异常
requests.URLRequired URL缺失异常
requests.TooManyRedirects超过最大重定向次数
requests.ConnectTimeout连接远程服务器超时异常,仅连接
requests.Timeout请求URL超时产生异常,全过程
r.raise_for_status()
如果不是200,产生异常requests. HTTPError
#requests尝试
import requests
r = requests.get("http://lexue.bit.edu.cn/504.html")
r.encoding = 'utf-8'
print(r.text)
print(r.status_code)
type(r)
r.headers
#爬取网页常用代码
import requests
def getHTMLText(url):
try:
r = requests.get(url,timeout=30)
r.raise_for_status()
#如果状态不是200,引发HTTPError异常
r.encoding = r.apparent_encoding
return r.text
except:
return "异常"
url = "www.baidu.com"
print(getHTMLText(url))
#爬取京东
import requests
r = requests.get("https://item.jd.com/100007652174.html")
print(r.status_code)
print(r.encoding)
print(r.text[:1000])
#爬取亚马逊
import requests
url="https://www.amazon.cn/dp/B07746N2J9/ref=sr_1_1?__mk_zh_CN=%E4%BA%9A%E9%A9%AC%E9%80%8A%E7%BD%91%E7%AB%99&keywords=kindle&qid=1583392394&sr=8-1"
r = requests.get(url)
print(r.status_code)
print(r.encoding)
#r.encoding = r.apparent_encoding
#print(r.text[:1000])
print(r.request.headers)
print("\n以上查询信息到错误信息,下面来修改访问方式")
kv = {
'user-agent':'Mozilla/5.0'}
r = requests.get(url,headers=kv)
print(r.status_code)
print("此时访问状态正常")
print(r.text[1000:2000])
#百度网页提交
import requests
#baidu API:
#http://www.baidu.com/s?wd= keyword
#360 API:
#http://www.so.com/s?q= keyword
kv = {
'wd':'Python'}
r = requests.get("http://www.baidu.com/s",params=kv)
print(r.status_code)
print("以下告知我们请求baidu的信息")
r.raise_for_status()
print(r.request.url)
print("长度为:{}".format(len(r.text)))
print(r.text[:1000])
import requests
path = "E:/abc.mp4"
url = "http://lexue.bit.edu.cn/pluginfile.php/232851/mod_folder/content/0/%E8%A7%86%E9%A2%91/%E6%95%99%E5%AD%A6%E8%A7%86%E9%A2%91%EF%BC%88%E6%8E%88%E8%AF%BE%E5%BD%95%E5%83%8F%EF%BC%89/6.5%20%E6%A0%B7%E5%BC%8F%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%EF%BC%8826%E5%88%86%E9%92%9F%EF%BC%8C55M%EF%BC%89.mp4"
r = requests.get(url)
print(r.status_code)
with open(path, 'wb') as f:
f.write(r.content)
f.close
#ip查询
import requests
url="http://www.ip138.com/ip.php?ip="
r = requests.get(url+"202.204.80.112")
print(r.status_code)
print(r.text[-500:])
HTTP协议
基于请求与响应模式的,无状态的应用层协议
URL: https://host[:port][path]
post:端口号,缺省值为80
path:请求资源的路径
requests.request(method, url, **kwargs)
method:请求方式
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:控制访问的参数 13个
params:字典或字节序列,作为参数增加到url中
data:字典、字节序列或文件对象,作为Request内容
json:JSON格式的数据,作为Request内容
headers:字典,HTTP定制头
cookies:字典或CookieJar, Request中的cookie
auth:元组,支持HTTP认证功能
files:字典类型,传输文件
timeout:设定超时时间,单位:s
proxies:字典类型,设定访问代理服务器,增加登录认证
allow_redirects: True/False,默认为True,重定向开关
stream:True/False,默认为True,获取内容立即下载开关
verify:True/False,默认为True,认证SSL证书开关
cert:本地SSL证书路径
requests.get(url,params=None,**kwargs)
**kwargs:12个,除了params
requests.head(url, **kwargs)
requests.post(url,data=None,json=None,**kwargs)
**kwargs:11个,除了data, json
requests.put(url,data=None, **kwargs)
**kwargs:12个,除了data
requests.patch(url,data=None, **kwargs)
**kwargs:12个,除了data
requests.delete(url, **kwargs)
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
print(soup.head)
print("子目录:",end="")
print(soup.head.contents)
print("")
print(soup.body.contents)
print("儿子有几个?{}".format(len(soup.body.contents)))
print("打印第一个:",end="")
print(soup.body.contents[1])
#优化HTML可读性
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
#设置换行来优化
print(soup.prettify())
Beautiful Soup库
<p class= “titlr”>…</p>标签
名称,属性
Tag:标签,最基本的信息组织单元,用<></>标明开头结尾
Name:标签的名字,
Attributes:标签的属性,字典形式组织,用.attrs
NavigableString:标签内非属性字符串<>…</>中字符串,
<tag>.string
Comment:标签内字符串的注释部分,一种特殊的Comment类型
HTML结构:
下行遍历:
.contents 获得子节点列表
.children 子节点的迭代类型,与content类似
.descendants子孙节点迭代类型,包含所有子孙节点
上行遍历:
.parent节点的父亲标签
.parents节点先辈标签的迭代类型
平行遍历:
.next_sibling 返回按HTML文本顺序的下一个平行节点标签
.previous_sibling返回按HTML文本顺序的上一个平行节点标签
.next_siblings迭代类型,返回后续所有平行节点标签
.previuos_siblings迭代类型,返回前续所有平行节点标签
#测试
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
#print(demo)
soup = BeautifulSoup(demo, "html.parser")
#print(soup.prettify())#全部内容
print(soup.title)
print(soup.a)#获取"链接"标签
print(soup.a.name)#获取a标签的名字
print(soup.a.parent.name)#获得上一层标签名字
print(soup.a.parent.parent.name)#获得上上一层标签名字
print(soup.a.attrs)#获取标签和属性
print(soup.a.attrs['class'])#获取属性字典对应的值
print(soup.a.attrs['class'])#获取属性字典对应的值
print(type(soup.a.attrs))#这是一个字典类型
print(soup.a.string)
print("ssssssssssssssssssssssssss")
print(soup.p)
print(soup.p.string)
#查找链接
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
for link in soup.find_all("a"):
print(link.get('href'))
#分类提取
from bs4 import BeautifulSoup
import requests
import re
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
for tag in soup.find_all(re.compile('b')):
print(tag.name)
#仅提取b中的tag
print(soup.find_all('p','course'))
print(soup.find_all(id='link1'))
print(soup.find_all(id='link'))
print(soup.find_all(id=re.compile('link')))
#信息展示
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
print(soup.find_all('a'))
print(soup.find_all(['a','b']))
#大学排名A
#CrawUnivRankingA.py
from bs4 import BeautifulSoup
import requests
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('td')
ulist.append([tds[0].string, tds[1].string, tds[3].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.com/zuihaodaxuepaiming2019.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 18)
main()
#大学排名B
#CrawUnivRankingB.py
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('td')
ulist.append([tds[0].string, tds[1].string, tds[3].string])
def printUnivList(ulist, num):
tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
print(tplt.format("排名","学校名称","总分",chr(12288)))
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.com/zuihaodaxuepaiming2019.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 20 univs
#股票信息查询A
#CrawBaiduStocksA.py
import requests
from bs4 import BeautifulSoup
import traceback
import re
def getHTMLText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
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):
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' )
except:
traceback.print_exc()
continue
def main():
stock_list_url = 'https://quote.eastmoney.com/stocklist.html'
stock_info_url = 'https://gupiao.baidu.com/stock/'
output_file = 'D:/BaiduStockInfo.txt'
slist=[]
getStockList(slist, stock_list_url)
getStockInfo(slist, stock_info_url, output_file)
main()
#股票信息查询B
#CrawBaiduStocksB.py
import requests
from bs4 import BeautifulSoup
import traceback
import re
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, "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':'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 = 'https://quote.eastmoney.com/stocklist.html'
stock_info_url = 'https://gupiao.baidu.com/stock/'
output_file = 'D:/BaiduStockInfo.txt'
slist=[]
getStockList(slist, stock_list_url)
getStockInfo(slist, stock_info_url, output_file)
main()
# CrowTaobaoPrice.py
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 = 'book'
depth = 3
start_url = 'https://s.taobao.com/search?q=' + goods + '&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&initiative_id=tbindexz_20170306&bcoffset=3&ntoffset=3&p4ppushleft=1%2C48'
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()
正则表达式:
.表示任何单个字符
[]字符集,对单个字符给出取值范围[abc]表示a,b,c
[^]非字符集, 对单个字符给出排除范围
*
字符0次或无限次扩展,abc*
表示ab,abc,abcc,abccc
+字符1次或无限次扩展,abc+
表示abc,abcc,abccc
?字符0次或1次扩展,abc?
表示ab,abc
|左右表达式任意一个
{m}
扩展字符m次,ab{2}c
表示abbc
{m,n}
扩展字符m至n次含n, ab{1,2}c
表示abc,abbc
^
匹配字符串开头,^abc
表示abc且在一个字符串的开头
$
匹配字符串结尾,abc$
表示abc且在一个字符串的结尾
()
分组标记,内部只能使用| (abc)
表示abc,(abc|def)
或
\d
数字,等价于[0-9]
\w
单词字符,等价于[A-Z,a-z,0-9,_]
实例:
P(Y|YT|YTH|YTHO)?N PN,PYN,PYTN,PYTHN,PYTHON
PY[TH]ON PYTON,PYHON
PY{:3}N PN,PYN,PYYN,PYYYN
经典正则表达式实例:
^[A-Za-z]+$
26个字母
^[A-Za-z0-9]+$
26个字母加数字组成的字符串
^-?\d+$
正负整数
^[0-9]*[1-9][0-9]*$
正整数
[1-9]\d{5}
6位邮政编码
[\u4e00-\u9fa5]
匹配中文字符
(([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])
IP地址0-255
re库采用raw string类型表示正则表达式,表示为:r‘text’
raw string 不包含转义符的字符串
Re库主要功能函数:
- re.search()
在一个字符串中搜索匹配正则表达式,返回match对象
re.search(pattern,string,flags=0)
pattern原文段, string待匹配字符串
flags:
re.I 忽略大小写,[A-Z]能匹配小写字符
re.M 将开始部分变为每行的开始的部分
re.S .匹配所有字符包括换行 - re.match()
在一个字符串的开始位置起搜索匹配正则表达式,返回match对象
re.match(pattern,string,flags=0)
pattern原文段, string待匹配字符串
flags:
re.I 忽略大小写,[A-Z]能匹配小写字符
re.M 将开始部分变为每行的开始的部分
re.S .匹配所有字符包括换行 - re.findall()
搜索字符串,以列表类型返回全部能匹配的子串
re.findall(pattern,string,flags=0)
pattern原文段, string待匹配字符串
flags:
re.I 忽略大小写,[A-Z]能匹配小写字符
re.M 将开始部分变为每行的开始的部分
re.S .匹配所有字符包括换行 - re.split()
将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.split(pattern,string,maxsplit=0,flags=0)
pattern原文段, string待匹配字符串
maxsplit:最大分割数,剩余部分作为最后一个元素输出
flags:
re.I 忽略大小写,[A-Z]能匹配小写字符
re.M 将开始部分变为每行的开始的部分
re.S .匹配所有字符包括换行 - re.finditer()
搜索字符串,返回一个匹配结果的迭代类型,适用于for
re.finditer(pattern,string,flags=0)
pattern原文段, string待匹配字符串
flags:
re.I 忽略大小写,[A-Z]能匹配小写字符
re.M 将开始部分变为每行的开始的部分
re.S .匹配所有字符包括换行 - re.sub()替换符合的内容,返回替换后的字符串
re.sub(pattern,repl,string,count=0,flags=0)
pattern原文段
repl:替换匹配字符串的字符串
string待匹配字符串
flags:
re.I 忽略大小写,[A-Z]能匹配小写字符
re.M 将开始部分变为每行的开始的部分
re.S .匹配所有字符包括换行
count:匹配的最大替换次数
Match对象的属性:
.string 待匹配文本
.re 匹配时使用的pattern对象
.pos 正则表达式搜索文本开始位置
.endpos正则表达式搜索文本结束位置
Match对象的方法:
.group(0) 获得匹配后的字符串
.start()匹配字符串在原始字符串的开始位置
.end()匹配字符串在原始字符串的结束位置
.span() 返回(.start(),.end())
贪婪匹配:默认即输出最长的子串
>>>match = re.search(r‘PY.*N’,‘PYANBNCNDN’)
>>>match.group(0)
‘PYANBNCNDN’
最小匹配:最小匹配
>>>match = re.search(r‘PY.*?N’,‘PYANBNCNDN’)
>>>match.group(0)
‘PYAN’
最小匹配操作符:
*? 前一个字符0次或无限次扩展
+? 前一个字符1次或无限次扩展
?? 前一个字符0次或1次扩展
{m,n} 扩展前一个字符m至n次含n
Scrapy框架
Engine:
不需要用户修改
控制所有模块之间的数据流
根据条件触发事件
Downloader:
不需要用户修改
根据请求下载网页
Scheduler:
不需要用户修改
对所有爬取请求进行调度管理
Downloader Middleware为使用户修改Downloader形成:
目的:实现Engine Downloader Scheduler之间用户配置
功能:修改,丢弃,新增请求或响应
Spider:
需要用户编写配置代码
解析Downloader返回的响应(Response)
产生爬取项(scraped item)
产生额外的爬取请求(Request)
Item Pipelines:
以流水线方式处理Spider产生的爬取项
由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline
可能操作包括:清理,检验和查重爬取项中的HTML数据,将数据存到数据库
Spider Middleware:
用户编写配置代码
目的:对请求和爬取项再处理
功能:修改,丢弃,新增请求或爬取项
Requests VS Scrapy
两者都不可处理js,提交表单,应对验证码等功能
Scrapy命令行格式:>scrapy<command>[options][args]
scrapy startproject [dir] 创建一个新工程
scrapy genspider [options] 创建一个爬虫
scrapy settings [options] 获得爬虫配置信息
scrapy crawl 运行一个爬虫
scrapy list 列出工程中所有爬虫
scrapy shell [url] 启动URl 调试命令行
创建项目:
scrapy startproject python123demo
python123demo/ 外层目录
scrapy.cfg 部署Scrapy 爬虫的配置文件
python123demo/ Scrapy框架的用户自定义Python代码
init.py 初始化脚本,无需修改
items.py Items代码模板(继承类)
middlewares.py Middlewares 代码模板(继承类)
pipelines.py Pipelines代码模板(继承类)
settings.py Scrapy 爬虫的配置文件
spiders/ Spiders代码模板目录(继承类)
init.py 初始文件,无需修改
pycache/ 缓存目录,无需修改
在工程中产生爬虫
scrapy genspider demo python123.io生成一个名为demo的spider
-*- 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爬取请求
配置产生的spider爬虫
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)
也可以修改为:
def start_requests(self):
urls = [ 'http://python123.io/ws/demo.html' ]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
yield 关键字
生成器是一个不断产生值的函数
包含yield语句的函数是一个生成器
生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值
yield写法:
>>> def gen(n):
for i in range(n):
yield i**2
>>> for i in gen(5):
print(i)
普通写法:
>>> def square(n):
ls = [i**2 for I in range(n)]
return ls
>>> for i in square(5):
print(i)
Scrapy爬虫的使用步骤:
- 创建一个工程和Spider模板
- 编写Spider
- 编写Item Pipeline
- 优化配置策略
Scrapy爬虫的数据类型:
Request 类
Response 类
Item 类
Request类:
class scrapy.http.Request()
Request对象表示一个HTTP请求
由Spider生成,由Downloader执行
.url Request对应的请求URl地址
.method 对应的请求方法, ‘GET’ ‘POST’等
.headers 字典类型风格的请求头
.body 请求内容主题,字符串类型
.meta 用户添加的扩展信息,在Scrapy内部模块间传递信息使用
.copy() 复制该请求
Response类:
class scrapy.http.Response()
Response对象表示一个HTTP响应
由Downloader生成,由Spider处理
.url Response对应的请求URl地址
.status HTTP状态码,默认是200
.headers Response对应的头部信息
.body Response对应的内容信息,字符串类型
.flags 一组标记
.request产生Response类型对应的Request对象
.copy() 复制该响应
Item类:
class scrapy.item.Item()
Item对象表示一个从HTML页面中提取的信息内容
由Spider生成,由Item Pipeline处理
Item类似字典类型,可以按照字典类型操作
可以使用CSS Selector:
<HTML>.css(‘a::atter(href)’).extract()
标签名称 标签属性
settings.py文件
CONCURRENT_REQUESTS Downloader最大并发请求下载数量,默认32
CONCURRENT_ITEMS Item Pipeline最大并发ITEM处理数量,默认100
CONCURRENT_REQUESTS_PER_DOMAIN每个目标域名最大的并发请求数量,默认8
CONCURRENT_REQUESTS_PER_IP 每个目标IP最大的并发请求数量,默认0,非0有效