当前位置: 首页 > news >正文

建设学校网站前的需求分析wordpress内嵌网页

建设学校网站前的需求分析,wordpress内嵌网页,招聘网站建设保定,宁波人流初次学习爬虫#xff0c;知识笔记小分享 学scrapy框架可看#xff1a;孤寒者博主的【Python爬虫必备—#xff1e;Scrapy框架快速入门篇——上】 目录#x1f31f; 一、#x1f349;基础知识二、#x1f349;http协议#xff1a;三、#x1f349;解析网页(1) xpath的用… 初次学习爬虫知识笔记小分享 学scrapy框架可看孤寒者博主的【Python爬虫必备—Scrapy框架快速入门篇——上】 目录 一、基础知识二、http协议三、解析网页(1) xpath的用法(2) bs4解析器的解释(3) python字符编码的错误(4) 正则表达式(5) 拓展知识 四、Requests库(1) Requests(2) Response对象的属性(3) 理解Requests库的异常(4) 请求数据 (** kwargs参数) 五、网络爬虫的“盗亦有道”(1) 网络爬虫的尺寸(2) 网络爬虫引发的问题(3) 网络爬虫的限制(4) Robots协议(5) 对Robots协议的理解 六、实战案例(1) 京东商品页面的爬取(2) 亚马逊商品页面的爬取(3) 百度360搜索关键词提交(4) 网络图片的爬取和存储(5) ip地址归属地的自动获取 七、Beautiful Soup库入门(1) 标签基本元素(2) 标签树下的下行遍历(3) 标签树的上行遍历(4) 标签树的平衡遍历 八、信息组织与提取方法(1) 信息标记的三种形式(2) 信息提取的一般方法(3) find_all()方法 九、实例中国大学排名爬虫(1) 程序的结构设计(2) 中文对齐的问题的原因 十、正则表达式(1) 正则表达式的概述(2) 正则表达式的语法和使用(3) 正则表达式的常用操作符(4) re库主要功能函数 十一、实例淘宝商品信息定向爬虫(1) 功能描述(2) 程序的结构设计 十二、实例股票数据定向爬虫(1) 功能描述(2) 程序的结构设计 十三、网络爬虫框架(1) Scrapy爬虫框架结构1. 爬虫框架2. 52结构3. requests库和scrapy库的比较4. Scrapy 命令行大部分操作都是通过命令行来实现 (2) Scrapy爬虫基本使用1. 步骤1建立一个Scrapy爬虫工程2. 步骤2在工程中产生一个Scrapy爬虫3. 步骤3配置产生的spider 爬虫4. 步骤4运行爬虫获取网页5. yield 关键字【生成器】6. Scrapy爬虫的数据类型 (3) 实例股票数据Scrapy实例1. 步骤1建立工程和Spider模板2. 步骤2编写Spider3. 步骤3编写Pipelines4. 配置ITEM_PIPELINES选项5. 配置并发连接选项 一、基础知识 获取网页内容 http请求 学习requests库 方法 get方法活得数据post方法创建数据 解析网页内容 学习html网页结构学习beautiful soup库解析获取到的html内容提取信息 储存或者分析数据 二、http协议 (1) http、Hypertext Transfer Protocol超文本传输协议http是一个基于“请求与响应”模式的、无状态的应用层协议 (2)基本格式 scheme://host[:post#]/path/……/[?query-string] [#anchor] 名称解释scheme协议例如httphttpsftphost服务器的IP地址或者域名port#服务器的端口如果是走协议默认端口缺省端口80path访问资源的路径query-string参数发送给http服务器的数据anchor锚跳转到网页的指定锚点位置 当获取的网页代码出现乱码时可能就是编码格式不一样手动设置编码格式 请内容 . encoding’ 编码格式 ‘URL是通过HTTP协议存取资源的Internet路径一个URL对应一个数据资源 三、解析网页 (1) xpath的用法 表达式描述用法说明nodename选取此节点的所有子节点div选取div下的所有标签//从全局节点中选择节点任意位置均可//div选取整个HTML页面的所有div标签/选取某个节点下 的节点//head/title选取head标签下的title标签选取某个属性的节点//div[id]选取带有id属性的div标签.当前节点下./span选取当节点下的span标签【代码中威力强大】 etree.HTML(内容)将不是html的格式的内容转换成html etree.tostring(内容encoding‘UTF-8’).decode(‘UTF-8’):如果不是UTF-8编码格式的内容这里可以更改成UTF-8的内容 etree.parse(文件路径)parse对html导入python并解析 自定解析器 如果在浏览器上保存网页到本地在python中获取.html文件需要利用自定解析器来解析文件内容 # 自定解析器 parseretree.HTMLParser(encodingUTF-8) htmletree.parse(路径,parserparser) resultetree.tostring(html,encodingUTF-8).decode(UTF-8)xpath中的[1]表示第一个元素而python中的第一个是从0开始,例如[0] (2) bs4解析器的解释 解析器使用方法优势劣势python标准库soup BeautifulSoup(htmlt, ‘html.parser’)python内置标准库;执行速度适中python2.x或者python3.2x前的版本中文文档容错能力差lxml HTML解析器soup BeautifulSoup(html, ‘lxml’)速度快文档容错能力强需要安装c语言库lxml XML解析器soup BeautifulSoup(html, ‘xml’)速度快唯一支持XML的解析器需要安装c语言库html5libsoup BeautifulSoup(html, ‘html5lib’)最好的容错性以浏览器的方式解析文档生成HTML5格式的文档不依赖外部扩展库速度慢 可以使用列表的强制转换 1bs4的使用时soup获取的时bs4的元素类型 2使用list强制转换 获取全部的单个标签soup.find_all(‘标签’) 获取拥有指定属性的标签 soup.find_all(‘标签’属性的键值对)soup.find_all(‘标签’attrs{键值对1键值对2}) attrs是存储的是字典里面可以包含html的多个属性 获取多个指定属性的标签 soup.find_all(‘标签’属性的键值对1属性的键值对2) 如果在获取时出现python关键字与属性冲突时在获取的时候添加一个下划线 ’ _ ’ 例如 soup.find_all(divclass_position)获取标签属性值 ​ 方法1:通过下标方式提取 1.先锁定标签 alistsoup.find_all(a) for a in alist:hrefa[href]print(href)​ 方法2利用attrs参数提取 for a in alist:hrefa.attrs[href]print(href)获取标签内的文本信息:使用string方法 # 获取html的所有div标签从第二个开始 divssoup.find_all(div)[1:] # 利用循环输出每个标签 for div in divs:# 只提取标签下的字符串adiv.find_all(a)[0].string# 提取整个div下的字符串 divssoup.find_all(div)[1:] for div in divs:infoslist(div.stripped_strings) # stripped_strings方法是删除列表中的制表符例如: \n,\t等.get_text(stripTrue): 去除文本内容的前后空白 (3) python字符编码的错误 ​ UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xca in position 339: invalid continuation byte——错误的原因是尝试将字节数据解码为UTF-8编码的字符串时遇到了一个无效的起始字节。UTF-8是一种流行的Unicode字符编码它使用1到4个字节表示不同的Unicode字符。如果字节数据不符合UTF-8编码规则就会引发此错误。 解决方法 尝试使用其他编码格式 使用错误处理策略 ignore是忽略无效字符 content response.content.decode(UTF-8,errorsignore)尝试不同的编码方式 ​ 如果无法确定字节数据的正确编码方式可以尝试使用不同的编码方式进行解码直到找到一个可以成功解码的方式。可以使用try-except语句来捕获解码错误并尝试不同的编码方式 pythonCopy codedata b\xbc\xde\xcf\xbc encodings [utf-8, gbk, latin-1] # 按照可能的编码方式顺序进行尝试 decoded_data None # 找到合适的编码 for encoding in encodings:try:decoded_data data.decode(encoding)breakexcept UnicodeDecodeError:continue # 如果找不到则为None if decoded_data is None:print(无法解码字节数据) else:print(decoded_data)使用chardet库自动检测编码方式 如果无法确定字节数据的正确编码方式可以使用chardet库来自动检测编码方式。chardet是一个第三方库可以根据字节数据的特征自动检测编码方式。 安装库 pythonCopy codepip install chardet使用 pythonCopy codeimport chardet data b\xbc\xde\xcf\xbc result chardet.detect(data) encoding result[encoding] decoded_data data.decode(encoding)排错 在Python爬虫中即使代码看起来没有明显语法错误爬取的数据仍然可能为空这通常与以下因素有关 目标网站结构改变 如果爬虫是基于HTML结构编写的而目标网站进行了改版或更新原有的选择器如XPath或CSS Selector可能不再有效导致找不到预期的数据。 动态加载内容 网页上的数据可能是通过JavaScript动态加载的直接爬取HTML源代码可能无法获取这些数据。此时需要分析网页加载逻辑使用如Selenium、Pyppeteer等工具模拟浏览器行为或者通过分析Ajax请求来间接获取数据。 反爬策略 目标网站可能启用了反爬虫策略比如Cookies验证、User-Agent限制、IP封锁、验证码、登录验证等。这时需要针对这些策略进行相应的处理比如设置更真实的User-Agent、使用代理IP池、处理验证码或模拟登录。 请求参数不正确 请求头信息headers、cookies、POST数据等参数可能需要特殊配置才能获取数据如果缺少必要参数或参数不正确服务器可能不会返回有效数据。 网络问题 即使代码看似没问题网络连接不稳定或服务器端出现问题也可能导致无法获取数据。 解析逻辑错误 数据解析环节可能出现问题例如正则表达式匹配不正确或者在解析HTML或JSON时引用了不存在的键或属性。 API调用权限或频率限制 若爬取的是API接口可能存在调用频率限制、API密钥失效或没有必要的授权。 数据缓存问题 如果爬虫有缓存机制并且缓存了错误的结果新的爬取可能会直接读取缓存而非从服务器获取新数据。 要解决这个问题可以从以下几个步骤入手 检查并确认请求网址是否正确且能够正常访问使用开发者工具查看网页加载过程确认数据是如何加载和呈现的检查请求头和请求体是否符合目标网站的要求检查解析代码逻辑特别是提取数据的部分检测网络状况以及是否有反爬措施调整爬虫策略对于动态加载内容确保相应脚本能够正确执行或模拟针对可能出现的API限制合理安排请求间隔遵循网站的使用协议。 (4) 正则表达式 语法reslutre.match(‘匹配内容’内容文件) 输出匹配reslut.group() 正则表达式又称规则表达式Regular Expression是使用单个字符串来描述、匹配某个句法规则的字符串常被用来检索、替换那些符合某个模式规则的文本正则的三个基础方法import re1.1从头开始搜索开头第一个如果不匹配则匹配不成功re.match(匹配规则 被匹配字符串)1.2 搜索整个容器匹配则成功不匹配返回Nonere.search(匹配规则 被匹配字符串)1.3 匹配整个字符串找出全部匹配项re.findall(匹配规则 被匹配字符串)1.4 字符串的 r 标记表示当前字符串是原始字符串即内部的转义字符无效而是普通字符1.5 数量匹配1* 匹配前一个规则的字符出现0至无数次2 匹配前一个规则的字符出现1至无数次 就是至少有一次3 匹配前一个规则的字符出现0次或者1次4{m}:匹配前一个规则的字符出现m次5{m,}匹配前一个规则的字符出现最少m次6{m,n}匹配前一个规则的字符出现m到n次1.6 边界匹配1^ :匹配字符串开头2$ :匹配字符串结尾3\b :匹配一个单词的边界4\B :匹配非单词边界1.7 分组匹配1| :匹配左右任意一个表达式2() :将括号字符串作为一个分组import re # 练习 s itheima1. python2 !!666 ##itcast3 # 匹配 . 使用\. re1re.findall(r\.,s) print(re1) # 自定义匹配字符 使用[ ] re2re.findall(r[A-Z,\W],s) print(re2) # 匹配整数 使用\d re3re.findall(r\d,s) print(re3) # 匹配非数字 使用\D re4re.findall(r\D,s) print(re4) # 匹配空格 和tab 使用 \s re5re.findall(r\s,s) print(re5) # 匹配非空白 \S re6re.findall(r\S,s) print(re6) # 匹配单字符 如a-z A-Z 0—9 _\ re7re.findall(r\w,s) print(re7) # 匹配非单词字符 \W re8re.findall(r\W,s) print(re8) # 匹配账号只能由字母和数字组成长度限制6到10位 # 规则为 ^[0-9a-zA-Z]{6, 10}$ # 匹配QQ号要求纯数字长度5-11第一位不为0 # 规则为^[1-9][0-9]{4, 10} # [1-9]匹配第一位[0-9]匹配后面4到10位(5) 拓展知识 爬取图片是不需要解码的 contentresponse.content保存数据wb是写入比特流数值 with open(路径,wb) as f:f.write(content)四、Requests库 Python123 学习流程图 python的集成工具 文本工具类IDE集成工具类IDEIDLEPycharmNotepadWingSublime TextPyDev EclipseVim EmacsVisual StudioAtomAnaconda SpyderKomodo EditCanopy 推荐使用的是Sublime Text 、Wing 、Pycharm 、Anaconda (科学计算机和数据分析的专题) (1) Requests 自动爬取HTML页面自动网络请求提交 最常用的是get请求方法 方法说明requests.request()构造一个请求支撑以下各方法的基础方法requests.get()获取html网页的主要方法对应于http的getrequests.head()获取html网页头信息的方法对应于http的headrequests.post()向html网页提交post请求的方法对应于http的postrequests.put()向html网页提交put请求的方法对应于http的putrequests.patch()向html网页提交局部修改请求对应于http的patchrequests.delete()向html页面提交删除请求对应http的delete 理解patch和put的区别 假设url位置有一组数据UserInfo包括UserID、UserName等20个字段 需求用户修改了UserName其他不变 - 采用patch仅向url提交userName的局部更新请求 - 采用put必须将所有20个字段一并提交到url未提交字段被删除 patch的最主要好处节省网络带宽(2) Response对象的属性 请求获取html网页 属性说明r.statu_codehttp请求的返回状态200表示连接成功其他表示失败或者另有原因r.texthttp响应内容的字符串形式即url对应的页面内容r.encoding从http header中猜测的响应内容编码方式r.apparent_encoding从内容中分析出的响应内容编码方式(备选编码方式)r.contenthttp响应内容的二进制形式 (3) 理解Requests库的异常 网络连接有风险 异常处理很重要 异常说明requests.ConnectionError网络连接错位于异常如DNS查询失败拒绝连接等requests.HTTPErrorhttp错误异常requests.URLRequiredurl缺失异常requests.TooManyRedirects超过最大重定向次数产生重定向异常requests.ConnectTimeout连接远程服务器超时异常requests.Timeout请求URL超时产生超时异常r.raise_for_status() 【response】如果不是200产生异常requests.HTTPError 使用try……except排错框架 import requestsdef getHTMLText(url):try:rrequests.get(url,timeout30)# 如果状态不是200引发HTTPError异常r.raise_for_status()r.encodingr.apparent_encodingreturn r.textexcept:return 产生异常if __name__ __mian__:urlhttp://www.baidu.comprint(getHTMLText(url))(4) 请求数据 (** kwargs参数) requests.request(method,url,** kwargs) **kwargs:控制访问的参数均为可选项 method请求方式 参数说明1params跟在url连接后面查询搜索的含义字典或者字流格式2data终点作为向服务器提供或提交资源时使用字典、字节序列或文件对象作为Request的内容3jsonJSON格式的数据作为Request的内容4headers字典、HTTP定制头5cookies字典或CookieJarRequest中的cookie6auth元组支持HTTP认证功能7files字典类型传输文件8timeout设定超时时间秒为单位9poroxies字典类型设定访问代理服务器可以增加登录认证10allow_redirectsTrue/False,默认为True重定向开关11streamTrue/False,默认为True获取内容立即下载开关12verifyTrue/False,默认为True认证SSL证书开关13cert本地SSL证书路径 params import requests url https://example.com/search params {query: Python爬虫,page: 1 } response requests.get(url, paramsparams) # 最终得到url https://example.com/search?queryPython爬虫page1data import requests url https://example.com/login # 相当于填写表单数据如登录表单post请求 data {username: your_username,password: your_password } response requests.post(url, datadata) json json参数的作用是简化向API发送JSON数据的过程确保了数据的正确序列化和HTTP头部的恰当设置非常适合与那些期望接收JSON输入的现代Web服务交互。 import requests import json url https://api.example.com/data data {key: value,another_key: another_value } response requests.post(url, jsondata) # 注意requests库内部会自动将data转换为JSON字符串 # 并设置Content-Type为application/json # data是一个Python字典通过jsondata传递给requests.post方法后requests会将其转换为JSON字符串{key: value, another_key: another_value}并设置请求头以表明发送的是JSON格式的数据。headers 实际上是http头的相关域它对应了向某一个url访问时所发起的http头字段利用这个字段定制某个访问url的http的协议头 User-Agent: 指定客户端的信息很多网站会根据这个字段判断访问者是浏览器还是爬虫有时需要将其设置为常见的浏览器字符串来避免被识别为爬虫。Accept-Language: 指定客户端接受的语言种类可以帮助获取特定语言的网页内容。Content-Type: 当发送POST请求且包含请求体时这个字段指定了数据的格式如application/x-www-form-urlencoded、application/json等。Authorization: 如果网站需要认证可以通过这个字段提供Token或其他认证信息。 import requests url https://example.com headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3,Accept-Language: en-US,en;q0.9,zh-CN;q0.8,zh;q0.7, } response requests.get(url, headersheaders) # 模仿浏览器请求数据cookies 从http中解析cookies它可以是字典也可以是cookieJar形式 解释通过cookies参数携带相应的cookie信息可以使爬虫模拟已登录用户的行为访问那些需要登录后才能查看的内容。这在爬取需要身份验证的网站数据时尤为重要。 作用cookies参数在Python爬虫中的作用是模拟浏览器的cookie机制帮助爬虫程序绕过登录限制访问受保护的内容或是维持与服务器的会话状态提高数据抓取的准确性和效率。 import requests url https://example.com/userinfo cookies {sessionid: abcdef123456,user: example_user } response requests.get(url, cookiescookies)auth 字段是一个元组类型它是支持http认证功能的auth参数可以是一个元组通常包含用户名和密码或者是一个AuthBase的子类实例用于自定义认证方案。 # 基本HTTP认证 from requests.auth import HTTPBasicAuth url https://api.example.com/private username your_username password your_password response requests.get(url, authHTTPBasicAuth(username, password))# API密钥认证 class APITokenAuth(requests.auth.AuthBase):def __init__(self, token):self.token tokendef __call__(self, r):r.headers[Authorization] fToken {self.token}return r url https://api.example.com/data token your_api_token response requests.get(url, authAPITokenAuth(token))# OAuth认证 对于支持OAuth的API虽然直接通过auth参数处理可能较为复杂通常需要先通过一系列步骤获取访问令牌但也可以根据具体流程封装认证逻辑到自定义的AuthBase子类中。 通过合理使用auth参数Python爬虫能够安全有效地访问那些需要认证的资源确保了数据请求的合法性与安全性。files 如何使用files参数上传一个图片文件 import requests url https://example.com/upload file_path /path/to/your/image.jpg with open(file_path, rb) as file:files {image: (file_path, file, image/jpeg)} # 文件名文件对象MIME类型response requests.post(url, filesfiles) print(response.text)在这个例子中我们首先打开要上传的图片文件并以二进制模式读取(rb)。然后我们将文件信息构造成一个字典其中键 image 是服务器端预期接收文件的字段名值是一个元组包含文件名这里也可以是任意字符串服务器端可能会用作文件名、文件对象和文件的MIME类型。最后通过requests.post()方法发送POST请求并将这个字典作为files参数传入。 files参数的使用让Python爬虫能够执行涉及文件上传的任务如图片上传、文件分享网站的数据抓取等场景。 timeout 用于设置网络请求的超时时间如果一个请求超过指定的秒数还没有得到响应requests库将会抛出一个异常而不是无限期地等待下去 import requests url https://example.com timeout 5 # 设置超时时间为5秒 try:response requests.get(url, timeouttimeout)# 处理响应数据 except requests.exceptions.Timeout:# 超时处理逻辑print(请求超时) # 请求https://example.com在5秒内没有得到服务器的响应程序将不会一直等待而是立即执行except块中的代码打印出“请求超时”的信息proxies 解释proxies 参数用于配置HTTP或HTTPS代理服务器。代理服务器作为中间人可以接收你的爬虫程序发出的网络请求然后转发给目标服务器并将响应结果再返回给你的爬虫。 目的 匿名性隐藏真实IP地址防止被目标网站识别和封锁尤其是在进行大量请求时减少被封禁的风险。地域限制绕过通过选择不同地区的代理服务器可以访问地理位置受限的内容或服务比如某些网站仅对特定国家或地区开放。性能优化如果目标服务器对你的物理位置响应较慢使用地理位置更近的代理服务器可以加快访问速度。负载均衡和带宽管理企业级应用中可能会利用代理服务器来分配请求优化网络资源使用。 import requests proxies {http: http://代理服务器地址:端口,https: https://代理服务器地址:端口, } response requests.get(http://example.com, proxiesproxies)代码解释proxies参数是一个字典其中键为协议名“http” 或 “https”值为代理服务器的URL包括协议、地址和端口。这样所有通过requests发起的请求都会通过指定的代理服务器进行。 注意使用代理时应遵守目标网站的使用条款和服务协议合法合规地进行数据抓取尊重网站的Robots协议并尽量减少对目标服务器的负担。同时选择稳定可靠的代理服务对于爬虫的成功运行至关重要。 allow_redirects requests库会自动处理重定向即自动向新的URL发送请求。当设置为False时则不自动处理重定向而是直接返回原始的重定向响应。 import requests # 允许重定向 response requests.get(http://example.com/redirect, allow_redirectsTrue) print(response.url) # 最终重定向后的URL # 禁止重定向 response requests.get(http://example.com/redirect, allow_redirectsFalse) print(response.status_code) # 可能会得到一个重定向的状态码如301或302 print(response.headers[location]) # 获取重定向的目标URL而不是自动访问stream 解释在使用Python的requests库进行网络请求时stream参数是一个非常实用的选项它的主要作用是控制是否立即下载响应内容。当设置streamTrue时requests不会立即下载整个响应体而是等到你需要时才按需读取这对于大文件下载或者仅需处理部分响应内容的场景非常有用stream参数的作用 节省内存对于大型文件的下载如果直接下载整个响应体到内存中可能会消耗大量内存资源。使用streamTrue可以让数据边下载边处理减少内存占用。按需读取当你只想读取响应的一部分内容而不是全部时使用流式处理可以更加高效。例如你可能只需要检查响应的前几行来决定是否继续下载剩余内容。长时间运行的连接在某些情况下保持连接打开并逐步处理响应内容是有益的比如实时数据流处理。 import requests url http://example.com/large_file.zip response requests.get(url, streamTrue) # 检查请求是否成功 if response.status_code 200:# 打开一个本地文件用于保存下载的内容with open(large_file.zip, wb) as f:for chunk in response.iter_content(chunk_size1024): # 如果chunk不是空的才写入文件if chunk: f.write(chunk)verify verifyTrue这意味着requests会验证服务器的SSL证书确保与之建立的HTTPS连接是安全的可以防止中间人攻击。有时候你可能需要关闭这个验证比如在测试环境中或者当遇到自签名证书self-signed certificate或证书链不完整的情况这时可以将verify设置为False。不过这样做会降低安全性应该谨慎考虑并仅在确信不会导致安全问题的情况下使用。 import requests url https://example.com response requests.get(url, verifyFalse)cert cert参数可以接收一个表示客户端证书文件路径的字符串或者一个包含证书文件路径和私钥文件路径的元组。cert 参数用于指定HTTPS请求时的客户端证书。当目标网站或API需要客户端提供安全证书进行身份验证时就需要用到这个参数。这对于访问那些启用了客户端证书认证的HTTPS服务尤为重要比如一些内部系统、银行接口或是高度安全的API。 import requests url https://example.com/api/secure-endpoint cert /path/to/client.pem # 单个文件包含证书和私钥 # 或者如果证书和私钥分开 # cert (/path/to/cert.pem, /path/to/key.pem) response requests.get(url, certcert)五、网络爬虫的“盗亦有道” (1) 网络爬虫的尺寸 123小规模数据量爬取速度不敏感Requests库 90%中规模数据规模较大爬取速度敏感Scrapy库大规模搜索引擎爬取速度关键定制开发爬取网页 玩转网页爬取网站 爬取系列网站爬取全网 (2) 网络爬虫引发的问题 骚扰问题 网络爬虫的“性能骚扰”web服务器默认接收人类访问。受限于编写水平和目的网络爬虫将会为Web服务带来巨大的资源开销 法律风险 服务器上的数据有产权归属网络爬虫获取数据后牟利将带来法律风险 隐私泄露 网络爬虫可能具备突破简单访问控制的能力获得被保护数据从而泄露个人隐私 (3) 网络爬虫的限制 来源审查判断User-Agent进行限制 检查来访Http协议头的User-Agent域只响应浏览器或友好爬虫的访问 发布公告Robots协议 告知所有爬虫网站的爬取策略要求爬虫遵守 (4) Robots协议 RobotsRobots Exclusion Standard网络爬虫排除标准协议是机器人的意思。robots协议是放在网站的根目录上的如果一个网站无robots协议则是该网站允许所有爬虫爬取该网站所有的爬虫都要遵循robots协议。 作用网站告知网络爬虫哪些页面可以抓取哪些不行 形式在网站根目录下的robots.txt文件 robots协议基本语法 # disallow表示不允许爬取的内容 # *代表所有/代表根目录Robots协议的使用 网络爬虫自动或人工识别robots.txt再进行内容爬取。约束性Robots协议是建议但非约束性网络爬虫可以不遵守但存在法律风险。 (5) 对Robots协议的理解 123访问量很小可以遵守 访问量较大建议遵守非商业且偶尔建议遵守 商业利益必须遵守必须遵守爬取网页 玩转网页爬取网站 爬取系列网站爬取全网 例如 http://www.baidu.com/robots.txt http://www.news,sina.com.cn/robots.txt http://www.qq.com/robots.txt http://news.qq.com/robots.txt http://www.moe.edu.cn/robots.txt (无robots协议)六、实战案例 (1) 京东商品页面的爬取 import requests urlhttps://item.jd.com/100077414769.html try:rrequests.get(url)r.raise_for_status() # 如果状态码是200则正常运行r.encodingr.apparent_encodingprint(r.text[:1000]) except:print(爬取失败)(2) 亚马逊商品页面的爬取 import requestsurlhttps://www.amazon.cn/gp/product/B01M8L5Z3Y headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 } try:rrequests.get(url,headersheaders)r.raise_for_status() # 如果状态码是200则正常运行r.encodingr.apparent_encodingprint(r.text) except:print(爬取失败)(3) 百度360搜索关键词提交 百度的关键词接口 http://www.baidu.com/s?wdkeyword import requestsurlhttp://www.baidu.com/s try:kv{wd:Python}rrequests.get(url,paramskv)print(r.request.url)r.raise_for_status() # 如果状态码是200则正常运行print(r.request.url)print(r.text) except:print(爬取失败)360的关键词接口 http://www.so.com/s?qkeyword import requestsurlhttp://www.so.com/s try:kv{q:Python}rrequests.get(url,paramskv)print(r.request.url)r.raise_for_status() # 如果状态码是200则正常运行print(r.text) except:print(爬取失败)(4) 网络图片的爬取和存储 import requests import os urlhttp://image.nationalgeograhic.com.cn/2017/20170211061910157.jpg rootF://music// 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(爬取失败)(5) ip地址归属地的自动获取 import requestsurlhttp://m.ip138.com/ip.asp?ip try:rrequests.get(url202.204.80.112)r.raise_for_status()r.encodingr.apparent_encodingprint(r.text[-500:]) except:print(爬取失败)七、Beautiful Soup库入门 (1) 标签基本元素 基本元素说明Tag标签最基本的信息组织单元分别用和/标明开头和结尾Name标签的名字……的名字是‘p’格式.nameAttributes标签的属性字典形式组织格式.attrsNavigableString标签内非属性字符串……/中字符串格式.stringComment标签内字符串的注释部分一种特殊的Comment类型 最基本的信息单元 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html try:responserequests.get(url)response.raise_for_status()htmlresponse.textsoupBeautifulSoup(html,html.parser)titlesoup.titleasoup.aprint(title,a) except:print(爬取失败)标签的名字 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html try:responserequests.get(url)response.raise_for_status()htmlresponse.textsoupBeautifulSoup(html,html.parser)titlesoup.title.name # 获取标签的尖括号里面的内容print(title) except:print(爬取失败)标签属性 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html try:responserequests.get(url)response.raise_for_status()htmlresponse.textsoupBeautifulSoup(html,html.parser)asoup.aida.attrs # 查看a标签里的属性id_classa.attrs[href] # 获取属性的键值对就是属性内容print(id_class) except:print(爬取失败)标签内非属性字符串 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html try:responserequests.get(url)response.raise_for_status()htmlresponse.textsoupBeautifulSoup(html,html.parser)psoup.p.stringprint(p) except:print(爬取失败)标签内字符串的注释部分 from bs4 import BeautifulSoupsoupBeautifulSoup(b!--This is a comment--/bpThis is not a comment/p,html.parser)print(type(soup.b.string)) except:print(爬取失败)(2) 标签树下的下行遍历 属性说明.contents子节点的列表将所有儿子节点存入列表.children子节点的迭代类型与.contents类似用于循环遍历儿子节点.descendants子孙节点的迭代类型包含所有子孙节点用于循环遍历 遍历下行 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html responserequests.get(url) soupBeautifulSoup(response.text,html.parser) headsoup.head.contents bodysoup.body.contents print(head) print(body)遍历下行 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html responserequests.get(url) soupBeautifulSoup(response.text,html.parser) # 遍历儿子节点 for child in soup.body.children:print(child) # 遍历子孙节点 for child in soup.body.descendants:print(child)(3) 标签树的上行遍历 属性说明.parent节点的父亲标签.parents节点先辈标签的迭代类型用于循环遍历辈点 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html responserequests.get(url) soupBeautifulSoup(response.text,html.parser) titlesoup.title.parent print(title) for parent in soup.a.parents:if parent is None:print(parent)else:print(parent.name)(4) 标签树的平衡遍历 属性说明.next_sibling返回按照HTML文本顺序的下一个平行节点标签.previous_sibling返回按照HTML文本顺序的上一个平行节点标签.next_siblings迭代类型返回按照HTML文本顺序的后续所有平行节点标签.previous_siblings迭代类型返回按照HTML文本顺序的前续所有平行节点标签 import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html responserequests.get(url) soupBeautifulSoup(response.text,html.parser) a0soup.a.next_sibling print(a0) a1soup.a.next_sibling.next_sibling print(a1) a2soup.a.previous_sibling print(a2) a3soup.a.previous_sibling.previous_sibling print(a3) a4soup.a.parent print(a4) # 遍历后续节点 for sibling in soup.a.next_sibling:print(sibling) # 遍历前续节点 for sibling in soup.a.previous_sibling:print(sibling).prettify()为HTML文本及其内容增加更加”\n“ .prettofuy()可用与标签方法.prettift() import requests from bs4 import BeautifulSoup urlhttp://python123.io/ws/demo.html responserequests.get(url) soupBeautifulSoup(response.text,html.parser) print(soup.prettify())八、信息组织与提取方法 (1) 信息标记的三种形式 json key:value key:[value1,value2] key:{subkey:subvalue}信息有类型适合程序处理(js)较XML简洁移动应用云端和节点的信息通信无注释 yaml key:vlaue key:#Comment -vlaue1 -vlaue2 key:subkey:subvlaue信息无类型文本信息比例最高可读性好各类系统的配置文件有注释易读 xml name……/name 注释!-- --最早的通用信息标记语言可扩展性好但繁琐。Internet上的信息交互与传递 (2) 信息提取的一般方法 方法一 完整解析信息的标记形式再提取关键信息。XML、JSON、YAML 需要标记解析器 优点信息解析准确缺点提取过程繁琐速度慢。 方法二 无视标记形式直接搜索关键信息。对信息的文本查找函数即可。 优点提取过程简洁速度较快。缺点提取结果准确性与信息内容相关 融合方法 结合形式解析与搜索方法提取关键信息。XML、JSON、YAML、搜索。需要标记解析器及文本查找函数。 (3) find_all()方法 .find_all(name,attrs,recursive,string,**kwargs)返回一个列表类型存储查找的结果 name对标签名称的检索字符串 attrs对标签属性值的检索字符串可标注属性检索 recursive是否对子孙全部检索默认True string……/中字符串区域的检索字符串name import requests from bs4 import BeautifulSoup rrequests.get(http://python123.io/ws/demo.html).text soupBeautifulSoup(r,html.parser) # 单个标签查找 asoup.find_all(a) # 多个标签查找用列表 bsoup.find_all([a,b])import requests from bs4 import BeautifulSoup rrequests.get(http://python123.io/ws/demo.html).text soupBeautifulSoup(r,html.parser) for tag in soup.find_all(True):print(tag.name)# 返回结果html head title body p b p a aattrs import requests from bs4 import BeautifulSoup rrequests.get(http://python123.io/ws/demo.html).text soupBeautifulSoup(r,html.parser) # 属性的查找 link1soup.find_all(id[link1,class]) print(link1) psoup.find_all(p,course) print(p)import requests from bs4 import BeautifulSoup import re rrequests.get(http://python123.io/ws/demo.html).text soupBeautifulSoup(r,html.parser) # 利用正则表达式的函数compile搜索属性单词搜索 linksoup.find_all(idre.compile(lin)) print(link)recursive import requests from bs4 import BeautifulSoup import re rrequests.get(http://python123.io/ws/demo.html).text soupBeautifulSoup(r,html.parser) # 是否对子孙全部检索 asoup.find_all(a,recursiveFalse) print(a)string import requests from bs4 import BeautifulSoup import re rrequests.get(http://python123.io/ws/demo.html).text soupBeautifulSoup(r,html.parser) # 搜索字符串 strsoup.find_all(stringBasic Python) print(str) # 利用正则表达式搜索关键词 pythonsoup.find_all(stringre.compile(py)) print(python)拓展 方法说明.find()搜索且只返回一个结果字符串类型同.find_all参数.find_parents()在先辈节点中搜索返回列表类型同.find_all参数.find_parent()在先辈节点中返回一个结果字符串类型同.find_all参数.find_next_siblings()在后续平行节点中搜索返回列表类型同.find_all参数.find_next_sibling()在后续平行节点中返回一个结果字符串类型同.find_all参数.find_previous_siblings()在前序平行节点中搜索返回列表类型同.find_all参数.find_previous_sibling()在前序平行节点中返回一个结果字符串类型同.find_all参数 提取属性的方法 import requests from bs4 import BeautifulSoup rrequests.get(http://python123.io/ws/demo.html).text soupBeautifulSoup(r,html.parser) for link in soup.find_all(a):提取属性的三种方法print(link[href])print(link.get(href))print(link.attrs[href])特soup(…) 等价于 soup.find_all(…) 九、实例中国大学排名爬虫 (1) 程序的结构设计 步骤1从网络上获取大学排名网页内容——getHTMLText()步骤2提取网页内容中信息到合适的数据结构——fillUnivList()步骤3利用数据结构展示并输出结果——printUnivList() 【软科排名】2024年最新软科中国大学排名|中国最好大学排名 (shanghairanking.cn) (2) 中文对齐的问题的原因 :填充对齐宽度,.精度类型引导符号用于填充的单个字符左对齐 右对齐^剧中对齐槽的设定输出宽度数字的千位分隔符适用于整数和浮点数浮点数小数部分的精度或字符串的最大输出长度整数类型b,c,d,o,x,X浮点数类型e,E,f,% 中文对齐问题的解决当中文字符宽度不够时采用西文字符填充中西文字符占用宽度不同采用中文字符的空格填充chr(12288). 代码块Python网络爬虫与信息提取_中国大学MOOC(慕课) (icourse163.org) import bs4 import requests from bs4 import BeautifulSoup import redef getHTMLText(url):try:rrequests.get(url,timeout30)r.raise_for_status()r.encodingr.apparent_encodingreturn r.textexcept:return 网页信息爬取错误def fillUnivList(ulist, html):soup BeautifulSoup(html, html.parser)for tr in soup.find_all(tbody).children:# 检测tr标签的类型的类型如果tr标签的类型不是bs4库定义的tag类型将过滤掉if isinstance(tr,bs4.element.Tag):tdstr(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({:10}\t{:^6}\t{:^10}.format(排名,学校名称,总分))for i in range(num):uulist[i]print(tplt.format(u[0],u[1],u[2],chr(12288)))def main():uinfo[]urlhtmlgetHTMLText(url)fillUnivList(uinfo,html)printUnivList(uinfo,20) 十、正则表达式 (1) 正则表达式的概述 通用的字符串表达框架简洁表达一组字符串的表达式针对字符串表达“简洁”和“特征”思想的工具判断某字符串的特征归属 正则表达式在文本处理中十分常用 表达式文本类型的特征病毒、入侵等同时查找或替换一组字符串匹配字符串的全部或部分 (2) 正则表达式的语法和使用 语法 正则表达式语法由字符和操作符构成 P(Y|YT|YTH|YTHO)?N使用 编译将符合正则表达式语法的字符串转换成正则表达式特征。 (3) 正则表达式的常用操作符 操作符说明实例.表示任何单个字符除”\n“以外[ ]字符集对单个字符给出取值范围[abc]表示a、b、c[a-z]表示a到z单个字符[^ ]非字符集对单个字符给出排除范围[^abc]表示非a或b或c的单个字符*前一个字符0次或无限次扩展abc*表示ab、abc、abcc、abcc等前一个字符1次或无限次扩展abc表示abc、abcc、abccc等?前一个字符0次或1次扩展abc表示av、abc|左右表达式任意一个abc|def表示abc、def{m}扩展前一个字符m次ab{2}c表示abbc{m,n}扩展前一个字符m至n次(含n)ab{12}c表示abc、abbc^匹配字符串开头^abc表示abc且在一个字符串的开头$匹配字符串结尾abc$表示abc且在一个字符串的结尾()分组标记内部只能使用|操作符(abc)表示abc(abc|def)表示abc、def\d数字等价于[0-9]\w单词字符等价于[A-Za-z0-9] (4) re库主要功能函数 函数说明re.search(pattern, string)在一个字符串中搜索匹配正则表达式的第一个位置返回match对象re.match(pattern, string)从一个字符串的开始位置起匹配正则表达式返回match对象re.findall(pattern, string)搜索字符串以列表类型返回全部能匹配的子串re.split(pattern, string)将一个字符串按照正则表达式匹配结果进行分割返回列表类型re.finditer(pattern, string)搜索字符串返回一个匹配结果的迭代类型每个迭代元素是match对象re.sub(pattern, string)在一个字符串中替换所有匹配正则表达式的字串返回替换后的字符串re.compile(pattern[, flags])re.escape(string) re模块中常用函数的简单介绍 语法 re.函数(pattern, stringflags0)pattern正则表达式的字符串或原生字符串表示string待匹配字符串flags正则表达式使用时的控制标记 re.search(pattern, stringflags0): 在字符串中搜索匹配正则表达式pattern的第一个位置返回一个匹配对象如果没有找到匹配的则返回None。 import re match re.search(r\d, hello 123 world) if match:print(找到匹配:, match.group()) else:print(未找到匹配)re.match(pattern, stringflags0): 从字符串的起始位置匹配正则表达式pattern如果起始位置没有匹配到则返回None。注意这与search()不同search()会扫描整个字符串以查找匹配项。 match re.match(r\d, 123 hello world) if match:print(找到匹配:, match.group()) else:print(未找到匹配)re.findall(pattern, string): 返回字符串中所有与正则表达式pattern相匹配的所有非重叠匹配项的列表。如果未找到匹配项则返回空列表。 matches re.findall(r\b\w\b, Hello World! This is a test.) print(matches) # 输出[Hello, World, This, is, a, test]re.sub(pattern, repl, string, count0, flags): 将字符串中所有与正则表达式pattern匹配的部分替换为repl并返回修改后的字符串。count参数可以指定替换的最大次数默认为0表示替换所有匹配项。 result re.sub(r\d, NUMBER, hello 123 world 456) print(result) # 输出hello NUMBER world NUMBERre.compile(pattern[, flags]): 编译正则表达式字符串为一个正则表达式对象这样可以提高使用相同模式进行多次匹配的效率。 pattern re.compile(r\d) match pattern.match(123 hello) if match:print(找到匹配:, match.group())re.escape(string): 转义字符串中的特殊字符使得它们在正则表达式中作为字面值字符对待。 pattern re.compile(re.escape([) r\d re.escape(])) match pattern.search([123]) if match:print(找到匹配:, match.group())re.split(pattern,string,maxsplit0,flags0): 将一个字符串按照正则表达式匹配进行分割返回列表类型 maxsplit最大分割数剩余部分作为最后一个元素输出 import re result1re.split(r[1-9]\d{5},BIT100081 TSU100084) print(result1) result2re.split(r[1-9]\d{5},BIT100081 TSU100084,maxsplit1) print(result2)re.finditer(pattern, string): 搜索字符串返回一个匹配结果的迭代类型每个迭代元素是match对象 import re for m in re.finditer(r[1-9]\d{5},BIT100081 TSU100084):if m:print(m.group(0))拓展: re库的另一种等价用法 # 第一种 函数式用法一次性操作 rstre.search(r[1-9]\d{5},BIT 100081) # 第二种 面对对象用法编译后的多次操作 patree.compile(r[1-9]\d{5}) rstpat.search(BIT 100081)match对象介绍 Match对象一次匹配的结果包含匹配的很多信息 import re matchre.search(r[1-9]\d{5},BIT 100081) if match:print(match.group(0))print(type(match))match对象的属性 属性说明.string待匹配的文本.re匹配时使用的patter对象正则表达式.pos正则表达式搜索文本的开始位置.endpos正则表达式搜索文本的结束位置match对象的方法 方法说明.group(0)获得匹配的字符串.start()匹配字符串在原始字符串的开始位置.end()匹配字符串在原始字符串的结束位置.span()返回(.start(),.end())import re matchre.search(r[1-9]\d{5},BIT100081 TSU100084) print(match.string) print(match.re) print(match.pos) print(match.endpos) print(match.group(0)) print(match.start()) print(match.end()) print(match.span())贪婪匹配 Re默认采用贪婪匹配即输出匹配最长的字串 import re matchre.search(rPY.*N,PYANBNCNDN) print(match.group(0))最小匹配如何输出最短的子串呢 import re matchre.search(rPY.*?N,PYANBNCNDN) print(match.group(0))最小匹配操作符 操作符说明*前一个字符0次或无限次扩展最小匹配前一个字符1次或无限次扩展最小匹配前一个字符0次或1次扩展最小匹配{mn}扩展前一个字符m至n次含n最小匹配 典型例子 在Python中可以使用re模块正则表达式模块来匹配IP地址。一个基本的IPv4地址由四个0到255之间的数字组成每部分之间用点(“.”)分隔。下面是一个简单的例子展示了如何编写一个正则表达式来匹配这样的IP地址 import redef is_valid_ip(ip):# 定义IP地址的正则表达式ip_pattern re.compile(r^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)# 使用正则表达式匹配IP地址if ip_pattern.match(ip):return Trueelse:return Falseif __name__ __main__:# 测试函数ips [192.168.1.1, 255.255.255.255, 123.456.789.0, 1.2.3]for ip in ips:print(f{ip}: {is_valid_ip(ip)})这段代码首先导入了re模块并定义了一个函数is_valid_ip该函数使用一个正则表达式来检查输入的字符串是否符合IPv4地址的格式。正则表达式的详细解释如下 ^表示字符串的开始。((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}这部分匹配前三部分的数字每部分数字范围是0到255后面跟着一个点(“.”)。其中 25[0-5] 匹配从250到255的数字2[0-4][0-9] 匹配从200到249的数字[01]?[0-9][0-9]? 匹配0到199的数字包括前导零的情况。\. 表示匹配点字符本身因为点在正则表达式中有特殊含义所以需要用反斜杠转义。 (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$这部分匹配第四部分的数字后面跟上字符串的结束标志$。 经典正则表达式实例 表达式解释^ [A-Z a-z]$由26个字母组成的字符串^ [A-Z a-Z 0-9]$由26个字母和数字组成的字符串^-?\d$整数形式的字符串^ [0-9] * [1-9] [0-9] * $正整数形式的字符串[1-9] \d{5}中国境内邮政编码6位[\u 4e00-\u9fa5]匹配中文字符\d {3}-d{8}|\d{4}-\d{7}国内电话号码010-68913536 十一、实例淘宝商品信息定向爬虫 (1) 功能描述 目标获取淘宝搜索页面的信息提取其中的商品名称和价格理解淘宝的搜索接口、翻页的处理技术路线requests-re (2) 程序的结构设计 步骤1提交商品搜索请求循坏获取页面。 https://s.taobao.com/search?initiative_idstaobaoz_20240525page1q%E4%B9%A6%E5%8C%85taball https://s.taobao.com/search?initiative_idstaobaoz_20240525page2q%E4%B9%A6%E5%8C%85taball https://s.taobao.com/search?initiative_idstaobaoz_20240525page3q%E4%B9%A6%E5%8C%85taball https://s.taobao.com/search?page2q%E4%B9%A6%E5%8C%85taball https://s.taobao.com/search?page1q%E4%B9%A6%E5%8C%85taball https://s.taobao.com/search?page3q%E4%B9%A6%E5%8C%85taball步骤2对于每个页面提取商品名称和价格信息 步骤3将信息输出到屏幕上。 代码块 #CrowTaobaoPrice.py import requests import redef getHTMLText(url):try:r requests.get(url, timeout30)r.raise_for_status()r.encoding r.apparent_encodingreturn r.textexcept: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 0for g in ilt:count count 1print(tplt.format(count, g[0], g[1]))def main():goods 书包depth 3start_url https://s.taobao.com/search?q goodsinfoList []for i in range(depth):try:url start_url s str(44*i)html getHTMLText(url)parsePage(infoList, html)except:continueprintGoodsList(infoList)main()十二、实例股票数据定向爬虫 (1) 功能描述 目标获取上交所和深交所所有股票的名称和交易信息输出保存到文件中技术路线requests-bs4-re 候选数据网站的选择 新浪股票:http://finance.sina.com.cn/stock/ 百度股票:https://gupiao.baidu.com/stock/选取原则股票信息静态存在于HTML页面中非js代码生成没有Robots协议限制。选取方法浏览器F12源代码查看等。选取心态不要纠结于某个网络多找信息源选择尝试 (2) 程序的结构设计 东方财富网http://quote.eastmoney.com/stocklist.html 百度股票https://gupiao.baidu.com/stock/ 单个股票https://gupiao.baidu.com/stock/sz002439.html步骤1从东方财富网获取股票列表 步骤2根据股票列表逐个到百度股票获取个股信息 步骤3将结果存储到文件 代码块 #CrawBaiduStocksB.py import requests from bs4 import BeautifulSoup import traceback import redef getHTMLText(url, codeutf-8):try:r requests.get(url)r.raise_for_status()r.encoding codereturn r.textexcept: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:continuedef getStockInfo(lst, stockURL, fpath):count 0for stock in lst:url stockURL stock .htmlhtml getHTMLText(url)try:if html:continueinfoDict {}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].textval valueList[i].textinfoDict[key] valwith open(fpath, a, encodingutf-8) as f:f.write( str(infoDict) \n )count count 1print(\r当前进度: {:.2f}%.format(count*100/len(lst)),end)except:count count 1print(\r当前进度: {:.2f}%.format(count*100/len(lst)),end)continuedef main():stock_list_url http://quote.eastmoney.com/stocklist.htmlstock_info_url https://gupiao.baidu.com/stock/output_file D:/BaiduStockInfo.txtslist[]getStockList(slist, stock_list_url)getStockInfo(slist, stock_info_url, output_file)main()十三、网络爬虫框架 (1) Scrapy爬虫框架结构 1. 爬虫框架 爬虫框架是实现爬虫功能的一个软件结构和功能组件集合爬虫框架是一个半成品能够帮助用户实现专业网络爬虫 2. 52结构 数据流的三个路径 Engine从Spider处获得爬取请求RequestsEngine将爬取请求转发给Scheduler用于调度Engine从Scheduler处获得下一个要爬取的请求Engine将爬取请求通过中间件发送给Downloader爬取网页后Downloader形成响应Response通过中间件发给EngineEngine将收到的响应通过中间件发送给Spider处理Spider处理响应后产生爬取项scraped Item和新的爬取请求requests给EngineEngine将爬取项发送给Item Pipeline框架出口Engine将爬取请求发送给Scheduler 数据流的出入口 Engine控制各模块数据流不间断从Scheduler处获得爬取请求直至请求为空 框架入口Spider的初始爬取请求 框架出口Item Pipeline Engine不需要用户修改 控制所有模块之间的数据流根据条件触发事件 Downloader不需要用户修改 根据请求下载页面 Scheduler不需要用户修改 对所有爬取请求进行调度管理 Spider需要用户编写配置代码 解析Downloader返回的响应Response产生爬取项scraped item产生额外的爬取请求Request Item Pipelines 以流水线方式处理Spider 产生的爬取项。由一组操作顺序组成类似流水线每一个操作是一个Item Pipeline类型可能操作包括清理、检验和查重爬取项中的HTML数据、将数据存储到数据库。 Downloader Middleware : 用户可以编写配置代码 # 目的实施Engine、Scheduler和Downloader之间进行用户可配置的控制 # 功能修改、丢弃、新增请求或响应Spider Middleware用户可以编写配置代码 # 目的对请求和爬取项的再处理 # 功能修改、丢弃、新增请求或爬取项3. requests库和scrapy库的比较 相同点 两者都可以进行页面请求和爬取Python爬虫的两个重要技术路线。两者可用性都好文档丰富入门简单。两者都没有处理js、提交表单、应对验证码等功能可扩展 不同点 requestsScrapy页面级爬虫网站级爬虫功能库框架并发性考虑不足性能较差并发性性能较好终点在于页面下载终点在于爬虫结构定制灵活一般定制灵活深度定制困难上手十分简单入门稍难 选用哪个技术路线开发爬虫 非常小的需求requests库不太小的需求Scrapy框架定制程度很高的需求不考虑规模自搭框架requests Scrapy 4. Scrapy 命令行大部分操作都是通过命令行来实现 Scrapy是为持续运行设计的专业爬虫框架提供操作的Scraoy命令行 Scrapy命令行格式 scrapy command[options][args]序号命令说明格式1startproject创建一个新工程scrapy startproject [dir]2genspider创建一个爬虫scrapy gebspider [options] 3settings获得爬虫配置信息scrapy settings [options]4crawl运行一个爬虫scrapy crawl 5list列出工程中所有爬虫scrapy list6shell启动URL调试命令行scrapy shell [url] 注1、2、4常用 Scrapy爬虫的命令行逻辑 为什么Scrapy采用命令行创建和运行爬虫 命令行不是图形界面更容易自动化适合脚本控制本质上Scrapy是给程序用的功能而不是界面更重要。 (2) Scrapy爬虫基本使用 Scrapy爬虫的使用步骤 步骤1创建一个工程和Spider模板步骤2编写Spider步骤3Item Pipeline步骤4优化配置策略 1. 步骤1建立一个Scrapy爬虫工程 创建工程生成工程目录python123demo/【外层目录】包含scrapy.cfg【部署Scrapy爬虫的配置文件】生成的工程目录 python123demo/外层目录 scrapy.cfg部署Scrapy爬虫的配置文件 python123demo/Scrapy框架的用户自定义的配置文件 __int__.py初始化脚本 items.pyItems代码模块继承类 middlewares.pyMiddlewares代码模块继承类 pipelines.pyPipelines代码模块继承类 settings.pyScrapy爬虫的配置文件 spiders/Spiders代码模块目录继承类 D:\E: E:\ cd \Hui\爬虫\自修案例 # 创建工程 E:\Hui\爬虫\自修案例scrapy startproject python123demo New Scrapy project python123demo, using template directory D:\Software\python3.12.2\Lib\site-packages\scrapy\templates\project, created in:E:\Hui\爬虫\自修案例\python123demoYou can start your first spider with:cd python123demoscrapy genspider example example.com 2. 步骤2在工程中产生一个Scrapy爬虫 # 创建demo文件 E:\Hui\爬虫\自修案例cd python123demo E:\Hui\爬虫\自修案例\python123demoscrapy genspider demo python123.io Created spider demo using template basic in module:python123demo.spiders.demospiders/Spiders代码模块目录继承类 __init__.py初始文件无需修改 __pycache__缓存目录无需修改 import scrapyclass DemoSpider(scrapy.Spider):# 当前爬虫的名字name demo# 最开始用户提交给命令行的域名指的是爬虫在爬取网站的时候它只能爬取这个域名以下的相关链接allowed_domains [python123.io]# 以列表形式包含的一个或多个url就是scrapy框架所要爬取的初始页面start_urls [https://python123.io]#解析页面的空方法用于处理响应解析内容形成字典发现新的url爬取请求def parse(self, response):pass 3. 步骤3配置产生的spider 爬虫 初始化url地址获取页面后的解析方式 import scrapyclass DemoSpider(scrapy.Spider):# 当前爬虫的名字name demo# 最开始用户提交给命令行的域名指的是爬虫在爬取网站的时候它只能爬取这个域名以下的相关链接# allowed_domains [python123.io]# 以列表形式包含的一个或多个url就是scrapy框架所要爬取的初始页面start_urls [http://python123.io/ws/demo.html]#解析页面的空方法用于处理响应解析内容形成字典发现新的url爬取请求def parse(self, response):# 将response响应的内容写入html文件中fnaemresponse.url.split(/)[-1]with open(fnaem,wb) as f:f.write(response.body)self.log(fSaved file {name})pass4. 步骤4运行爬虫获取网页 保存在E:\Hui\爬虫\自修案例\python123demo 路径下为demo.html E:\Hui\爬虫\自修案例\python123demoscrapy crawl demo 2024-05-26 15:39:40 [scrapy.utils.log] INFO: Scrapy 2.11.2 started (bot: python123demo) 2024-05-26 15:39:40 [scrapy.utils.log] INFO: Versions: lxml 5.2.1.0, libxml2 2.11.7, cssselect 1.2.0, parsel 1.9.1, w3lib 2.1.2, Twisted 24.3.0, Python 3.12.2 (tags/v3.12.2:6abddd9, Feb 6 2024, 21:26:36) [MSC v.1937 64 bit (AMD64)], pyOpenSSL 24.1.0 (OpenSSL 3.2.1 30 Jan 2024), cryptography 42.0.7, Platform Windows-11-10.0.22631-SP0 2024-05-26 15:39:40 [scrapy.addons] INFO: Enabled addons: [] 2024-05-26 15:39:40 [asyncio] DEBUG: Using selector: SelectSelector 2024-05-26 15:39:40 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor 2024-05-26 15:39:40 [scrapy.utils.log] DEBUG: Using asyncio event loop: asyncio.windows_events._WindowsSelectorEventLoop 2024-05-26 15:39:40 [scrapy.extensions.telnet] INFO: Telnet Password: 77de2e6d491b1e81 2024-05-26 15:39:40 [scrapy.middleware] INFO: Enabled extensions: [scrapy.extensions.corestats.CoreStats,scrapy.extensions.telnet.TelnetConsole,scrapy.extensions.logstats.LogStats] 2024-05-26 15:39:40 [scrapy.crawler] INFO: Overridden settings: {BOT_NAME: python123demo,FEED_EXPORT_ENCODING: utf-8,NEWSPIDER_MODULE: python123demo.spiders,REQUEST_FINGERPRINTER_IMPLEMENTATION: 2.7,ROBOTSTXT_OBEY: True,SPIDER_MODULES: [python123demo.spiders],TWISTED_REACTOR: twisted.internet.asyncioreactor.AsyncioSelectorReactor} 2024-05-26 15:39:40 [scrapy.middleware] INFO: Enabled downloader middlewares: [scrapy.downloadermiddlewares.offsite.OffsiteMiddleware,scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware,scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware,scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware,scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware,scrapy.downloadermiddlewares.useragent.UserAgentMiddleware,scrapy.downloadermiddlewares.retry.RetryMiddleware,scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware,scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware,scrapy.downloadermiddlewares.redirect.RedirectMiddleware,scrapy.downloadermiddlewares.cookies.CookiesMiddleware,scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware,scrapy.downloadermiddlewares.stats.DownloaderStats] 2024-05-26 15:39:40 [scrapy.middleware] INFO: Enabled spider middlewares: [scrapy.spidermiddlewares.httperror.HttpErrorMiddleware,scrapy.spidermiddlewares.referer.RefererMiddleware,scrapy.spidermiddlewares.urllength.UrlLengthMiddleware,scrapy.spidermiddlewares.depth.DepthMiddleware] 2024-05-26 15:39:40 [scrapy.middleware] INFO: Enabled item pipelines: [] 2024-05-26 15:39:40 [scrapy.core.engine] INFO: Spider opened 2024-05-26 15:39:40 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2024-05-26 15:39:40 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023 2024-05-26 15:39:41 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to GET https://python123.io/robots.txt from GET http://python123.io/robots.txt 2024-05-26 15:39:41 [scrapy.core.engine] DEBUG: Crawled (404) GET https://python123.io/robots.txt (referer: None) 2024-05-26 15:39:41 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to GET https://python123.io/ws/demo.html from GET http://python123.io/ws/demo.html 2024-05-26 15:39:41 [scrapy.core.engine] DEBUG: Crawled (200) GET https://python123.io/ws/demo.html (referer: None) 2024-05-26 15:39:41 [scrapy.core.scraper] ERROR: Spider error processing GET https://python123.io/ws/demo.html (referer: None) Traceback (most recent call last):File D:\Software\python3.12.2\Lib\site-packages\twisted\internet\defer.py, line 1078, in _runCallbackscurrent.result callback( # type: ignore[misc]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File D:\Software\python3.12.2\Lib\site-packages\scrapy\spiders\__init__.py, line 82, in _parsereturn self.parse(response, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File E:\Hui\爬虫\自修案例\python123demo\python123demo\spiders\demo.py, line 18, in parseself.log(fSaved file {name})^^^^ NameError: name name is not defined. Did you mean: self.name? 2024-05-26 15:39:41 [scrapy.core.engine] INFO: Closing spider (finished) 2024-05-26 15:39:41 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {downloader/request_bytes: 896,downloader/request_count: 4,downloader/request_method_count/GET: 4,downloader/response_bytes: 1981,downloader/response_count: 4,downloader/response_status_count/200: 1,downloader/response_status_count/301: 2,downloader/response_status_count/404: 1,elapsed_time_seconds: 0.954325,finish_reason: finished,finish_time: datetime.datetime(2024, 5, 26, 7, 39, 41, 875924, tzinfodatetime.timezone.utc),log_count/DEBUG: 7,log_count/ERROR: 1,log_count/INFO: 10,response_received_count: 2,robotstxt/request_count: 1,robotstxt/response_count: 1,robotstxt/response_status_count/404: 1,scheduler/dequeued: 2,scheduler/dequeued/memory: 2,scheduler/enqueued: 2,scheduler/enqueued/memory: 2,spider_exceptions/NameError: 1,start_time: datetime.datetime(2024, 5, 26, 7, 39, 40, 921599, tzinfodatetime.timezone.utc)} 2024-05-26 15:39:41 [scrapy.core.engine] INFO: Spider closed (finished)5. yield 关键字【生成器】 生成器是一个不断产生值的函数包含yield语句的函数时一个生成器生成器每次产生一个值yield语句函数被冻结被唤醒后再产生一个值。 普通写法 import scrapyclass DemoSpider(scrapy.Spider):# 当前爬虫的名字name demo# 最开始用户提交给命令行的域名指的是爬虫在爬取网站的时候它只能爬取这个域名以下的相关链接# allowed_domains [python123.io]# 以列表形式包含的一个或多个url就是scrapy框架所要爬取的初始页面start_urls [http://python123.io/ws/demo.html]#解析页面的空方法用于处理响应解析内容形成字典发现新的url爬取请求def parse(self, response):# 将response响应的内容写入html文件中fnaemresponse.url.split(/)[-1]with open(fnaem,wb) as f:f.write(response.body)self.log(fSaved file {name})pass生成器yield写法 import scrapyclass DemoSpider(scrapy.Spider):name demodef start_requests(self):urls[http://python123.io/ws/dem.html]for url in urls:yield scrapy.Request(urlurl,callbackself.parse)def parse(self,response):fnameresponse.url.split()[-1]with open(fname,wb) as f:f.write(response.body)self.log(fSaved file {fname})yield一般都是于for循环连用例如 # 生成器写法 def gen(n):for i in range(n):yield i**2for i in gen(5):print(i, ,end)#普通写法 def square(n):ls [i**2 for i in range(n)]return lsfor i in square(5):print(i, ,end)6. Scrapy爬虫的数据类型 Request类 class scrapy.http.Request(): Request对象表示一个HTTP请求由Spider生成由Downloader执行 属性或方法说明.urlRequest对应的请求url地址.method对应的请求方法‘GET’‘PODT’等.headers字典类型风格的请求头.body请求内容主体字符串类型.meta用户添加的扩展信息在Scrapy内部模块间传递信息使用.copy()复制该请求 Response类 class scrapy.http.Response(): Response对象表示一个HTTP响应。由Downloader生成由Spider处理 属性或方法说明.urlResponse对应的请求url地址.statusHTTP状态码默认是200.headersRespnse对应的头部信息.bodyResponse对应的内容信息字符串类型.flags一组标记.request产生Response类型对应的Request对象.copy()复制该响应 Item类 class scrapy.item.Item(): Item对象表示一个从HTML页面中提取的信息内容由Spider生成由Item Pipeline处理。Item类型字典类型可以按照字典类型操作。 Scrapy爬虫提取信息的方法 Scrapy爬虫支持多种HTML信息提取方法 Beautiful Soup lxml re Xpath Selector CSS Selector # CSS Selector的基本使用CSS Selector由W3C组织维护并规范 HTML.css(a::attr(href)).extract() #a标签名称 href标签属性(3) 实例股票数据Scrapy实例 1. 步骤1建立工程和Spider模板 打开终端winR输入cmd建立工程 # 进入文件 D:\cd \Software\pycharm\web_request # 创建工程其文件中包含BaiduStocks 文件和 scrapy.cfg 文件 D:\Software\pycharm\web_requestscrapy startproject BaiduStocks New Scrapy project BaiduStocks, using template directory D:\Software\python3.12.2\Lib\site-packages\scrapy\templates\project, created in:D:\Software\pycharm\web_request\BaiduStocksYou can start your first spider with:cd BaiduStocksscrapy genspider example example.com # 切换视图 D:\Software\pycharm\web_requestcd BaiduStocks # 创建爬虫 spiders模板 D:\Software\pycharm\web_request\BaiduStocksscrapy genspider stocks baidu.com Created spider stocks using template basic in module:BaiduStocks.spiders.stocks进一步修改spiders/stocks.py文件 2. 步骤2编写Spider 配置stocks.py文件修改对返回页面的处理修改对新增URL爬取请求的处理 import scrapy import reclass StocksSpider(scrapy.Spider):name stocksallowed_domains [baidu.com]start_urls [http://quote.eastmoney.com/stocklist.html]def parse(self,response):# 对这个页面的所有a标签进行提取# 使用CSS选择器来定位HTML中的元素# .extract()这个方法应用于前面的选择器表达式结果上用于从选择器匹配到的所有元素中提取出实际的文本内容。for href in response.css(a::attr(href)).extract():try:# 匹配正确的url链接stockre.findall(r[s][hz]\d{6},href)[0]# 组成个股链接urlhttps://gupiao.baidu.com/stock/stock.htmlyield scrapy.Request(url,callbackself.parse_stock)except:continuedef 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(len(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] valinfoDict.update({股票名称: re.findall(\s.*\(, name)[0].split()[0] \re.findall(\.*\, name)[0][1:-1]})yield infoDict3. 步骤3编写Pipelines 配置pipelines.py文件定义对爬虫取项Scraped Item的处理类 class BaidustocksPipeline(object):def process_item(self, item, spider):return itemclass 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)) \nself.f.write(line)except:passreturn item4. 配置ITEM_PIPELINES选项 配置settings.py文件 ITEM_PIPELINES {BaiduStocks.pipelines.BaidustocksInfoPipeline: 300, }程序运行 D:\Software\pycharm\web_request\BaiduStocksscrapy crawl stocks D:\Software\pycharm\web_request\BaiduStocks\BaiduStocks\spiders\stocks.py:39: SyntaxWarning: invalid escape sequence \s{股票名称: re.findall(\s.*\(, name)[0].split()[0] \ D:\Software\pycharm\web_request\BaiduStocks\BaiduStocks\spiders\stocks.py:40: SyntaxWarning: invalid escape sequence \re.findall(\.*\, name)[0][1:-1]}) 2024-05-27 18:01:29 [scrapy.utils.log] INFO: Scrapy 2.11.2 started (bot: BaiduStocks) 2024-05-27 18:01:29 [scrapy.utils.log] INFO: Versions: lxml 5.2.1.0, libxml2 2.11.7, cssselect 1.2.0, parsel 1.9.1, w3lib 2.1.2, Twisted 24.3.0, Python 3.12.2 (tags/v3.12.2:6abddd9, Feb 6 2024, 21:26:36) [MSC v.1937 64 bit (AMD64)], pyOpenSSL 24.1.0 (OpenSSL 3.2.1 30 Jan 2024), cryptography 42.0.7, Platform Windows-11-10.0.22631-SP0 2024-05-27 18:01:29 [scrapy.addons] INFO: Enabled addons: [] 2024-05-27 18:01:29 [asyncio] DEBUG: Using selector: SelectSelector 2024-05-27 18:01:29 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor 2024-05-27 18:01:29 [scrapy.utils.log] DEBUG: Using asyncio event loop: asyncio.windows_events._WindowsSelectorEventLoop 2024-05-27 18:01:29 [scrapy.extensions.telnet] INFO: Telnet Password: 3876dc1b1227236a 2024-05-27 18:01:29 [scrapy.middleware] INFO: Enabled extensions: [scrapy.extensions.corestats.CoreStats,scrapy.extensions.telnet.TelnetConsole,scrapy.extensions.logstats.LogStats] 2024-05-27 18:01:29 [scrapy.crawler] INFO: Overridden settings: {BOT_NAME: BaiduStocks,FEED_EXPORT_ENCODING: utf-8,NEWSPIDER_MODULE: BaiduStocks.spiders,REQUEST_FINGERPRINTER_IMPLEMENTATION: 2.7,ROBOTSTXT_OBEY: True,SPIDER_MODULES: [BaiduStocks.spiders],TWISTED_REACTOR: twisted.internet.asyncioreactor.AsyncioSelectorReactor} 2024-05-27 18:01:29 [scrapy.middleware] INFO: Enabled downloader middlewares: [scrapy.downloadermiddlewares.offsite.OffsiteMiddleware,scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware,scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware,scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware,scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware,scrapy.downloadermiddlewares.useragent.UserAgentMiddleware,scrapy.downloadermiddlewares.retry.RetryMiddleware,scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware,scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware,scrapy.downloadermiddlewares.redirect.RedirectMiddleware,scrapy.downloadermiddlewares.cookies.CookiesMiddleware,scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware,scrapy.downloadermiddlewares.stats.DownloaderStats] 2024-05-27 18:01:29 [scrapy.middleware] INFO: Enabled spider middlewares: [scrapy.spidermiddlewares.httperror.HttpErrorMiddleware,scrapy.spidermiddlewares.referer.RefererMiddleware,scrapy.spidermiddlewares.urllength.UrlLengthMiddleware,scrapy.spidermiddlewares.depth.DepthMiddleware] 2024-05-27 18:01:29 [scrapy.middleware] INFO: Enabled item pipelines: [BaiduStocks.pipelines.BaidustocksInfoPipeline] 2024-05-27 18:01:29 [scrapy.core.engine] INFO: Spider opened 2024-05-27 18:01:29 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2024-05-27 18:01:29 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023 2024-05-27 18:01:29 [scrapy.downloadermiddlewares.offsite] DEBUG: Filtered offsite request to quote.eastmoney.com: GET http://quote.eastmoney.com/robots.txt 2024-05-27 18:01:29 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (302) to GET http://quote.eastmoney.com/center/gridlist.html#hs_a_board from GET http://quote.eastmoney.com/stocklist.html 2024-05-27 18:01:30 [scrapy.core.engine] DEBUG: Crawled (200) GET http://quote.eastmoney.com/center/gridlist.html#hs_a_board (referer: None)5. 配置并发连接选项 settings.py文件 选项说明CONCURRENT_REQUESTSDownloader最大并发请求下载数量默认为32CONCURRENT_ITEMSItem Pipeline最大并发ITEM处理数量默认100CONCURRENT_REQUESTS_PER_DOMAIN每个目标域名最大的并发请求数量默认8CONCURRENT_REQUESTS_PER_IP每个目标IP最大的并发请求数量默认0非0有效
http://www.w-s-a.com/news/148488/

相关文章:

  • 网站建设与网页设计论述题软件开发公司在哪里
  • 二级网站建设方案模板亚马逊网站建设案例
  • 网站开发兼职团队门户网站如何制作
  • 高州市网站建设开发区招聘信息
  • 上海专业网站制作设计公司企业邮箱怎样注册
  • 网站建设在商标第几类网站建设 设计创意
  • 做一网站APP多少钱重庆中色十二冶金建设有限公司网站
  • 网上做效果图网站有哪些软件徐州泉山区建设局网站
  • 凯里网站制作网站篡改搜索引擎js
  • 如何使用凡科建设网站武安城乡建设网站
  • 网站建设网站及上传wordpress火车头发布
  • 有没有做网站的团队电脑版传奇网站
  • 建立企业网站公司医疗创意小产品设计
  • 深圳 做网站 车公庙免费的招标网有哪些
  • 网站在那里备案成都成华区网站建设
  • 做网站选哪家好搜索引擎优化的目标体系包括哪些
  • 做数据可视化的网站ppt2016是制作网页的软件
  • 济宁市建设工程质量监督站网站徐州网站优化推广
  • 北京网站设计多少钱php做商品网站
  • 能打开的网站你了解的彩票网站开发dadi163
  • 手机做网站价格优秀企业网站建设价格
  • 电商网站建设企业做网站的客户多吗
  • 有做思维图的网站吗西安建设市场诚信信息平台网站
  • 网站建设求职具备什么30岁学网站开发
  • 官方网站minecraft北京低价做网站
  • 网站建设报价兴田德润机械加工网络接单
  • 免费的推广网站安卓app制作平台
  • 长春火车站附近美食建设信用卡银行积分兑换商城网站
  • 网站提交网址如何备份wordpress网页
  • 龙腾盛世网站建设医院管理系统