1.当获取https链接是需要添加参数 validate_cert=False。
2.增加翻页操作
1 @config(age=10 * 24 * 60 * 60) 2 def index_page(self, response): 3 for each in response.doc(‘#thumbnail * > h2 > a‘).items(): 4 self.crawl(each.attr.href,validate_cert=False, callback=self.detail_page) 5 next = response.doc(‘.next‘) 6 self.crawl(next.attr.href,validate_cert=False,callback=self.index_page)
3.自定义工具类 参考https://vel.life/Pyspider%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97/
1 #!/usr/bin/env python 2 # -*- encoding: utf-8 -*- 3 # Created on 2017-12-05 20:59:56 4 # Project: boeing 5 6 from pyspider.libs.base_handler import * 7 import re 8 from pyspider.database.mysql.mysqldb import SQL 9 import sys 10 import os 11 import time as ti 12 from dateutil import parser 13 14 reload(sys) 15 sys.setdefaultencoding(‘utf8‘) 16 17 #图片存放目录 18 DIR_PATH = "./" 19 20 class Handler(BaseHandler): 21 22 headers= { 23 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 24 "Accept-Encoding":"gzip, deflate, sdch", 25 "Accept-Language":"zh-CN,zh;q=0.8", 26 "Cache-Control":"max-age=0", 27 "Connection":"keep-alive", 28 "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36" 29 } 30 31 crawl_config = { 32 ‘itag‘: ‘v1.1‘, 33 "headers" : headers, 34 "timeout" : 100000 35 } 36 37 def __init__(self): 38 self.dir_path = DIR_PATH 39 self.tool = Tool() 40 41 @every(minutes=24 * 60) 42 def on_start(self): 43 self.crawl(‘http://boeing.mediaroom.com/news-releases-statements‘, callback=self.index_page) 44 45 @config(age=10 * 24 * 60 * 60) 46 def index_page(self, response): 47 for each in response.doc(‘.archive_nav > a‘).items(): 48 year=each.text() 49 if(year != "Search"): 50 if(year=="2016" or year=="2015"): 51 self.crawl(each.attr.href, callback=self.news_page) 52 53 def news_page(self, response): 54 for each in response.doc(‘.item‘).items(): 55 time=each.find(‘div‘).eq(0).text() 56 datetime_struct = parser.parse(time) 57 time=datetime_struct.strftime(‘%Y-%m-%d‘) 58 self.crawl(each.find(‘div‘).find(‘a‘).attr.href, save={‘time‘: time},callback=self.news,connect_timeout = 5000, timeout = 20000) 59 for each_page in response.doc(‘.table_footer > b > a‘).items(): 60 self.crawl(each_page.attr.href, callback=self.news_page2) 61 62 def news_page2(self, response): 63 for each in response.doc(‘.item‘).items(): 64 time=each.find(‘div‘).eq(0).text() 65 datetime_struct = parser.parse(time) 66 time=datetime_struct.strftime(‘%Y-%m-%d‘) 67 self.crawl(each.find(‘div‘).find(‘a‘).attr.href, save={‘time‘: time},callback=self.news,connect_timeout = 5000, timeout = 20000) 68 69 def news(self, response): 70 time=response.save[‘time‘] 71 if response.doc(‘#assets_20295_130083-117_tab_link‘): 72 self.crawl(response.doc(‘#assets_20295_130083-117_tab_link‘).attr.href,save={‘time‘: time}, callback=self.detail_page,validate_cert=False,connect_timeout = 5000, timeout = 20000) 73 else: 74 self.crawl(response.url, save={‘time‘: time},callback=self.detail_page,validate_cert=False,connect_timeout = 5000, timeout = 20000) 75 76 @config(priority=2) 77 def detail_page(self, response): 78 title=response.doc(‘.wd_news_releases-detail > h1‘).text() 79 time=response.save[‘time‘] 80 content = ‘‘ 81 for each in response.doc(‘.news_body > p‘).items(): 82 content += each.text() 83 url = response.url 84 picture_url = ‘‘ 85 picture_local_path = ‘‘ 86 file_title = re.sub(‘[\/:*?"<>|]‘,‘-‘,title) 87 imgDir = self.dir_path 88 for imgElem in response.doc(‘.detail_image > img‘).items(): 89 imgUrl = imgElem.attr.src 90 picture_url += imgUrl + ‘;‘ 91 if imgUrl: 92 #获取图片文件后缀 93 extension = self.tool.get_extension(imgUrl) 94 name = self.tool.get_name(imgUrl) 95 #拼接图片名 96 file_name = name + "." + extension 97 picture_local_path += ‘;‘ + file_name 98 self.crawl(imgUrl,callback=self.save_img,save={"file_name":file_name, "imgDir":imgDir},validate_cert=False, connect_timeout = 5000, timeout = 20000) 99 100 for imgElem in response.doc(‘.PRN_ImbeddedAssetReference > p > img‘).items(): 101 imgUrl = imgElem.attr.src 102 picture_url += imgUrl + ‘;‘ 103 if imgUrl: 104 #获取图片文件后缀 105 extension = self.tool.get_extension(imgUrl) 106 name = self.tool.get_name(imgUrl) 107 #拼接图片名 108 file_name = name + "." + extension 109 picture_local_path += ‘;‘ + file_name 110 self.crawl(imgUrl,callback=self.save_img,save={"file_name":file_name, "imgDir":imgDir},validate_cert=False, connect_timeout = 5000, timeout = 30000) 111 112 return { 113 "title":title, 114 "introduction":"null", 115 "time":time, 116 "content":content, 117 "keywords":"null", 118 "name":"boeing", 119 "source":"原创", 120 "url":url, 121 "picture_url":picture_url, 122 "picture_local_path":picture_local_path 123 } 124 125 #保存图片 126 def save_img(self,response): 127 content = response.content 128 file_name = response.save["file_name"] 129 imgDir = response.save["imgDir"] 130 file_path = imgDir + file_name 131 self.tool.save_img(content,imgDir,file_path) 132 133 def on_result(self,result): 134 if not result or not result[‘title‘]: 135 return 136 sql = SQL() 137 sql.insert(‘boeing‘,**result) 138 139 #工具类 140 class Tool: 141 #保存图片 142 def save_img(self,content,imgDir,path): 143 if not os.path.exists(imgDir): 144 os.makedirs(imgDir) 145 f = open(path,"wb" ) 146 f.write(content) 147 f.close() 148 149 #获取url后缀名 150 def get_extension(self,url): 151 extension = url.split(".")[-1] 152 return extension 153 154 #获取图片名 155 def get_name(self,url): 156 name=url.split("/")[-1].split(".")[0] 157 return name
4.
1 #爬取模板:加注释版 2 #!/usr/bin/env python 3 # -*- encoding: utf-8 -*- 4 # Created on 2017-12-05 20:59:56 5 # Project: boeing 6 7 from pyspider.libs.base_handler import * 8 import re 9 from pyspider.database.mysql.mysqldb import SQL 10 import sys 11 import os 12 import time as ti 13 from dateutil import parser 14 15 reload(sys) 16 sys.setdefaultencoding(‘utf8‘) 17 18 #图片存放目录 19 DIR_PATH = "./" # pyspider默认目录? 20 21 class Handler(BaseHandler): 22 23 headers= { 24 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 25 "Accept-Encoding":"gzip, deflate, sdch", 26 "Accept-Language":"zh-CN,zh;q=0.8", 27 "Cache-Control":"max-age=0", 28 "Connection":"keep-alive", 29 "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36" 30 } 31 32 crawl_config = { 33 ‘itag‘: ‘v1.1‘, 34 "headers" : headers, 35 "timeout" : 100000 36 } 37 38 def __init__(self): 39 self.dir_path = DIR_PATH 40 self.tool = Tool() 41 42 @every(minutes=24 * 60) 43 def on_start(self): #这里设置你要爬取的网页,先登录看看是否对应,否则容易出错 44 self.crawl(‘http://boeing.mediaroom.com/news-releases-statements‘, callback=self.index_page) 45 46 @config(age=10 * 24 * 60 * 60) 47 def index_page(self, response): #设置索引页 48 for each in response.doc(‘.archive_nav > a‘).items(): 49 year=each.text() 50 if(year != "Search"): 51 if(year=="2016" or year=="2015"): #这里设置爬取网页新闻的年份(按年份分类),最好把最新的年份都爬取下来【注意,不是所有的网站都有这个分类!】 52 self.crawl(each.attr.href, callback=self.news_page) 53 54 #进入某一年份的index页面 55 def news_page(self, response): 56 for each in response.doc(‘.item‘).items(): 57 time=each.find(‘div‘).eq(0).text() # find‘div‘是找到.item下的所有元素,然后eq(0)获取第0个(首个)元素的text(),即内容 58 datetime_struct = parser.parse(time) 59 time=datetime_struct.strftime(‘%Y-%m-%d‘) # 这里的功能是,将网页代表时间的字符串格式化为%Y-%m-%d(原网页是英文格式) 60 self.crawl(each.find(‘div‘).find(‘a‘).attr.href, save={‘time‘: time},callback=self.news,connect_timeout = 5000, timeout = 20000) #调取新闻页。注意,所有的time都是提前在index页获取的,因此需要传递给最后的处理函数 61 for each_page in response.doc(‘.table_footer > b > a‘).items(): 62 self.crawl(each_page.attr.href, callback=self.news_page2) #调取其它新闻页 63 64 #基于该年份,调取其它index页(一个年份可能对应多个index页面,一个index页面又对应多个新闻页) 65 def news_page2(self, response): 66 for each in response.doc(‘.item‘).items(): 67 time=each.find(‘div‘).eq(0).text() #同理,以下 68 datetime_struct = parser.parse(time) 69 time=datetime_struct.strftime(‘%Y-%m-%d‘) 70 self.crawl(each.find(‘div‘).find(‘a‘).attr.href, save={‘time‘: time},callback=self.news,connect_timeout = 5000, timeout = 20000) # each.find(‘div‘).find(‘a‘).attr.href是获得新闻页的url 71 72 #主方法,进入新闻页 73 def news(self, response): 74 time=response.save[‘time‘] #记录已经格式化的时间,继续往下传递 75 if response.doc(‘#assets_20295_130083-117_tab_link‘): # 这里的if else是用来判断新闻有无图片 76 self.crawl(response.doc(‘#assets_20295_130083-117_tab_link‘).attr.href,save={‘time‘: time}, callback=self.detail_page,validate_cert=False,connect_timeout = 5000, timeout = 20000) 77 else: 78 self.crawl(response.url, save={‘time‘: time},callback=self.detail_page,validate_cert=False,connect_timeout = 5000, timeout = 20000) 79 80 @config(priority=2) 81 def detail_page(self, response): 82 title=response.doc(‘.wd_news_releases-detail > h1‘).text() #通过正则表达式获取新闻题目 83 time=response.save[‘time‘] #最终获取到时间 84 content = ‘‘ #初始化新闻内容为空,字符串 85 for each in response.doc(‘.news_body > p‘).items(): # 对于每一个在.news_body > p中的内容都添加到content中 86 content += each.text() 87 url = response.url # 保存网址为当前网址 88 picture_url = ‘‘ #与content同理 89 picture_local_path = ‘‘ 90 file_title = re.sub(‘[\/:*?"<>|]‘,‘-‘,title) # ???某个正则表达式? 91 imgDir = self.dir_path 92 #处理图片的方法1: 93 for imgElem in response.doc(‘.detail_image > img‘).items(): 94 imgUrl = imgElem.attr.src 95 picture_url += imgUrl + ‘;‘ 96 if imgUrl: 97 #获取图片文件后缀 98 extension = self.tool.get_extension(imgUrl) 99 name = self.tool.get_name(imgUrl) 100 #拼接图片名 101 file_name = name + "." + extension 102 picture_local_path += ‘;‘ + file_name 103 self.crawl(imgUrl,callback=self.save_img,save={"file_name":file_name, "imgDir":imgDir},validate_cert=False, connect_timeout = 5000, timeout = 20000) 104 #处理图片的方法2: 105 for imgElem in response.doc(‘.PRN_ImbeddedAssetReference > p > img‘).items(): 106 imgUrl = imgElem.attr.src 107 picture_url += imgUrl + ‘;‘ 108 if imgUrl: 109 #获取图片文件后缀 110 extension = self.tool.get_extension(imgUrl) 111 name = self.tool.get_name(imgUrl) 112 #拼接图片名 113 file_name = name + "." + extension 114 picture_local_path += ‘;‘ + file_name 115 self.crawl(imgUrl,callback=self.save_img,save={"file_name":file_name, "imgDir":imgDir},validate_cert=False, connect_timeout = 5000, timeout = 30000) 116 117 return { 118 "title":title, 119 "introduction":"null", 120 "time":time, 121 "content":content, 122 "keywords":"null", 123 "name":"boeing", #这里根据你建的表格名修改 124 "source":"原创", 125 "url":url, 126 "picture_url":picture_url, 127 "picture_local_path":picture_local_path 128 } 129 130 #保存图片 131 def save_img(self,response): 132 content = response.content 133 file_name = response.save["file_name"] 134 imgDir = response.save["imgDir"] 135 file_path = imgDir + file_name 136 self.tool.save_img(content,imgDir,file_path) 137 138 def on_result(self,result): 139 if not result or not result[‘title‘]: 140 return 141 sql = SQL() 142 sql.insert(‘boeing‘,**result) #这里也要对应修改哦 143 144 #工具类 145 class Tool: 146 #保存图片 147 def save_img(self,content,imgDir,path): 148 if not os.path.exists(imgDir): 149 os.makedirs(imgDir) 150 f = open(path,"wb" ) #写入文件 151 f.write(content) 152 f.close() 153 154 #获取url后缀名 155 def get_extension(self,url): 156 extension = url.split(".")[-1] 157 return extension 158 159 #获取图片名 160 def get_name(self,url): 161 name=url.split("/")[-1].split(".")[0] 162 return name
5.代码:功能for_compositesworld(复合材料世界)爬虫程序_详注
1 #!/usr/bin/env python 2 # -*- encoding: utf-8 -*- 3 # Created on 2018-03-18 18:13:33 4 # Project: compositesworld 5 #问题: 6 #1. 爬取introduction项的正则表达式不够准确,一部分项爬不下来 ---已解决(注意分析网站的html,而不是一味地依赖CSS选择器) 7 #2. 如何动态、高效地控制爬取的年份截止日期?比如,最早到2016.01.01 8 #3. 在单步调试,尝试调用保存图片函数时出现 Exception: HTTP 599:…… OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to d2n4wb9orp1vta.cloudfront.net:443 错误 ---已解决(似乎与网络连接状况有关,但正常运行时反而没什么问题。暂时忽略) 9 #4. python反反爬虫机制(代理IP。sleep延时:防止爬取过快导致封IP) ---已解决。 使用ti.sleep(t),t为参数,单位为秒。如:ti.time.sleep(3),表示停顿3秒后继续执行 10 11 from pyspider.libs.base_handler import * #这个库中定义了爬取的各种控制函数和方法 12 import re #re就是regular expression,即正则表达式。正则表达式(通项公式)是用来简洁表达一组字符串的表达式。优势是简洁,一行胜千言。这个库主要用于字符串匹配。 13 from pyspider.database.mysql.mysqldb import SQL 14 import sys #用于接下来修改编码格式 15 import os #OS库提供了使用各种操作系统功能的接口 16 import time as ti # 用于延时控制 17 from dateutil import parser #日期处理库,parser子库是根据字符串解析成datetime 18 19 #编码转换 20 reload(sys) #Python运行的时候首先加载了site.py,在site.py文件里有这么一段代码: 21 # if hasattr(sys, "setdefaultencoding"): 22 # del sys.setdefaultencoding 23 #可以看出,在sys加载后,setdefaultencoding方法被删除了,所以我们要通过重新导入sys来设置系统编码 24 sys.setdefaultencoding(‘utf8‘) #设置默认编码,UTF-8 25 26 #图片存放目录 27 DIR_PATH = "./" # ./ 的意思是:当前目录(登录pyspider时) 28 29 class Handler(BaseHandler): 30 31 headers= { 32 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 33 "Accept-Encoding":"gzip, deflate, sdch", 34 "Accept-Language":"zh-CN,zh;q=0.8", 35 "Cache-Control":"max-age=0", 36 "Connection":"keep-alive", 37 "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36" 38 } 39 40 crawl_config = { 41 ‘itag‘: ‘v1.1‘, #修改这个tag号,可以重新启动爬取 42 "headers" : headers, 43 "timeout" : 100000 44 } 45 46 47 def __init__(self): 48 self.dir_path = DIR_PATH 49 self.tool = Tool() 50 51 52 @every(minutes=24 * 60) # @every修饰器,表示每24小时会执行一次 53 def on_start(self): # 这里设置你要爬取的网页URL(最好是列表的形式,按更新顺序排列),先登录看看是否对应,否则容易出错 54 self.crawl(‘https://www.compositesworld.com/news/list‘,validate_cert=False, callback=self.index_page) # self.crawl 告诉 pyspider 抓取指定页面,然后使用 callback 函数对结果进行解析,并调用接下来的index_page 55 # 总结: 56 # 通过 on_start 回调函数,作为爬取的入口点,当点击主面板上的 run 的时候,就是调用这个函数,启动抓取。 57 # self.crawl 告诉调度器,我们需要抓取 ‘https://www.compositesworld.com/news/list‘ 这个页面,然后使用 callback=self.index_page 这个回调函数进行解析。 58 # 所有 return 的内容默认会被捕获到 resultdb 中,可以直接在 WEBUI 上看到(如果结果)。 59 60 61 @config(age=10 * 24 * 60 * 60) #在这表示我们认为 10 天内页面有效,不会再次进行更新抓取 62 #由此,注意,pyspider不会抓取同一个URL两次(永久丢弃),即使修改了代码,对于第一次运行该项目并修改并第二次运行该项目的初学者来说,这是非常常见的。 63 #以上是引述。但是,在实际操作WebUI时,通过单步调试可以很方便地抓取同一个页面。 64 def index_page(self, response): #设置索引页 65 for each in response.doc(‘.headline > a‘).items(): 66 self.crawl(each.attr.href, validate_cert=False,callback=self.detail_page) 67 next = response.doc(‘a[aria-label="Next"]‘) 68 self.crawl(next.attr.href,validate_cert=False, connect_timeout = 5000, timeout = 20000,callback=self.index_page) 69 # validate_cert=False 参数,用来解决SSL证书问题,对于以“https”开头的网站,必须添加 70 71 @config(priority=2) 72 def detail_page(self, response): 73 # 使用CSS正则表达式工具修改doc()中的路径,进行页面上的元素的采集 74 title = response.doc(‘.content-headline‘).text() 75 introduction = response.doc(‘.col-sm-12 > h1‘).text() 76 time = response.doc(‘.cell-vert-center > div > span‘).text() 77 time = time[10:] #我这里采用了截取字符段的形式,获得真正的时间字符子序列(不通用!!!) 78 datetime_struct = parser.parse(time) 79 time=datetime_struct.strftime(‘%Y-%m-%d‘) # 这里的功能是,将网页代表时间的字符串格式化为%Y-%m-%d(原网页是英文格式) 80 content = response.doc(‘#short > div > div > p‘).text() 81 url = response.url 82 picture_url = ‘‘ #与content同理 83 picture_local_path = ‘‘ 84 file_title = re.sub(‘[\/:*?"<>|]‘,‘-‘,title) 85 imgDir = self.dir_path 86 for imgElem in response.doc(‘picture > img‘).items(): 87 imgUrl = imgElem.attr.src 88 imgUrl = imgUrl[:-10] #为了截掉后面多余的字段";width=560",总共10个字符(不通用!!!) 89 picture_url += imgUrl + ‘;‘ 90 if imgUrl: 91 #获取图片文件后缀 92 extension = self.tool.get_extension(imgUrl) 93 name = self.tool.get_name(imgUrl) 94 #拼接图片名 95 file_name = name + "." + extension 96 picture_local_path += ‘;‘ + file_name 97 self.crawl(imgUrl,callback=self.save_img,save={"file_name":file_name, "imgDir":imgDir},validate_cert=False, connect_timeout = 5000, timeout = 20000) 98 # 这里回调了save_img函数,在单步调试时可以明显看到 99 100 # def detail_page(self, response)作为结果返回一个对象。 101 # 结果将被resultdb默认捕获。 102 # 可以通过覆盖on_result(self, result)自己管理结果的方法。 103 return { # 与你建立的表结构对应。这是python中的字典结构,即“键-值对” 104 "title":title, 105 "introduction":introduction, 106 "time":time, 107 "content":content, 108 "keywords":"null", 109 "name":"compositesworld", #这里根据你建的表格名修改 110 "source":"原创", 111 "url":url, 112 "picture_url":picture_url, 113 "picture_local_path":picture_local_path 114 } 115 116 117 #保存图片 118 def save_img(self,response): # 可以看到,上面save中保存的内容其实通过response传了过来 119 content = response.content # resp.content返回的是bytes型也就是二进制的数据,resp.text返回的是Unicode型的数据。 120 # 简而言之,如果你想取文本,可以通过r.text。 如果想取图片,文件,则可以通过r.content。 121 file_name = response.save["file_name"] 122 imgDir = response.save["imgDir"] 123 file_path = imgDir + file_name 124 self.tool.save_img(content,imgDir,file_path) 125 126 #数据存储函数:on_result方法 127 # 调试的时候建议将 on-result 整个移除,便于显示实时获取结果。最后再保存到数据库 128 def on_result(self,result): 129 if not result or not result[‘title‘]: # 如果没到最后,继续返回数据 130 return 131 sql = SQL() # 覆盖默认方法,使用mysqldb文件中定义的方法,连接数据库 132 sql.insert(‘compositesworld‘,**result) #将结果插入到表格。同理,这里根据你建的表格名修改 133 134 135 #工具类 136 class Tool: 137 #保存图片 138 def save_img(self,content,imgDir,path): 139 if not os.path.exists(imgDir): # os.path.exists(name)判断是否存在文件或目录name 140 os.makedirs(imgDir) # os.makedirs() 方法用于递归创建目录 141 f = open(path,"wb" ) # wb 以只写方式打开 142 f.write(content) # 写入文件 143 f.close() 144 145 #获取url后缀名 146 def get_extension(self,url): 147 extension = url.split(".")[-1] 148 return extension 149 150 #获取图片名 151 def get_name(self,url): 152 name=url.split("/")[-1].split(".")[0] 153 return name
6.封装for_jeccomposites(JEC)伪宏控制__范式编
1 #!/usr/bin/env python 2 # -*- encoding: utf-8 -*- 3 # Created on 2018-03-19 22:26:12 4 # Project: jeccomposites 5 #问题: 6 #1. 爬取下来的content是一连串的字符串,没有考虑到换行的问题,可能需要添加‘\n‘? 7 #2. 爬取这个网站的content似乎有一段开头是单独放在title的class后面的,或许添加该段? 8 #3. 是否应该增加一个 tag 标签属性,因为很多网站只有tag但没有keywords,或者两者认为一致? 9 #4. [Caution]图片存储功能出现异常错误。显示TypeError与‘NoneType‘和Unicode‘有关 ----已解决(第一,os.makedirs的返回值不是路径。改正这个之后。第二,非常坑!一个意想不到的意外错误!!!!与空格、制表符对齐的区别有关,两者不能混用!!!) 10 11 12 #**********************************************************************************----------~~~~~~~~\ 13 #伪宏控制__范式编程 14 #------(理论上)你只需要在这里[正确]填入所有信息,整个程序即可运行!【只适用于单一index的爬取。多重分类页面,或者需要对采集的数据做进一步规范化,则必须在后面相应地方改进】 15 project_name = "jeccomposites" #你的项目 的名称 16 website_url_initial = ‘http://www.jeccomposites.com/knowledge/international-composites-news‘ #你爬取的初始网页(index页) 的地址 17 detail_page_css = ‘.nodetitle > a‘ #新闻页面链接 的CSS表达式 18 next_page_css = ‘.pager-next > a‘ #下一页链接 的CSS表达式 19 title_css = ‘.content > h1‘ #新闻标题 的CSS表达式 20 introduction_css = ‘.content-block-txt > p‘ #新闻简介 的CSS表达式 21 time_css = ‘.content-block-txt > div‘ #发布时间 的CSS表达式 22 content_css = ‘.block-system > div > div div > div > p‘ #新闻内容 的CSS表达式 23 img_css = ‘.content > a > img‘ #新闻图片 的CSS表达式 24 keywords_css = ‘null‘ #关键词,一般页面中无,因此默认为空。#!【重要:如果其他的 *_css 在网页中也找不到对应项的话,可以填‘null‘,程序将自动返回空值】 25 source_declaration = "原创" #原创声明,一般不改动 26 #**********************************************************************************-----------~~~~~~~/ 27 28 from pyspider.libs.base_handler import * #这个库中定义了爬取的各种控制函数和方法 29 import re #re就是regular expression,即正则表达式。正则表达式(通项公式)是用来简洁表达一组字符串的表达式。优势是简洁,一行胜千言。这个库主要用于字符串匹配。 30 from pyspider.database.mysql.mysqldb import SQL 31 from pyspider.database.mysql.mysqldb_new import SQL as SQL_new 32 import sys #用于接下来修改编码格式 33 import os #OS库提供了使用各种操作系统功能的接口 34 import time as ti # 用于延时控制 35 from dateutil import parser #日期处理库,parser子库是根据字符串解析成datetime 36 37 #根据项目名称,自动创建表 38 sql_new = SQL_new() 39 sql_new.create_table(project_name) 40 41 42 #图片存放目录【在当前目录自动创建项目子目录,分类各项目的爬取内容。可实现多项目的同时爬取,而内容分开】 43 path_for_project = "./"+project_name+"/" # ./ 的意思是:当前目录(登录pyspider时) 44 if not os.path.exists(path_for_project): 45 os.makedirs(path_for_project) 46 DIR_PATH = path_for_project 47 else: 48 DIR_PATH = path_for_project 49 #注意哦,“data”文件夹是pyspider启动时自动生成的,其中的db文件是用来默认储存捕获的数据的。但是,我们已经实现了on_result方法把数据传给了Mysql,所以这data文件夹是不起作用的,因此可以忽略。 50 51 #编码转换 52 reload(sys) #Python运行的时候首先加载了site.py,在site.py文件里有这么一段代码: 53 # if hasattr(sys, "setdefaultencoding"): 54 # del sys.setdefaultencoding 55 #可以看出,在sys加载后,setdefaultencoding方法被删除了,所以我们要通过重新导入sys来设置系统编码 56 sys.setdefaultencoding(‘utf8‘) #设置默认编码,UTF-8 57 58 59 class Handler(BaseHandler): 60 61 headers= { 62 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 63 "Accept-Encoding":"gzip, deflate, sdch", 64 "Accept-Language":"zh-CN,zh;q=0.8", 65 "Cache-Control":"max-age=0", 66 "Connection":"keep-alive", 67 "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36" 68 } 69 70 crawl_config = { 71 ‘itag‘: ‘v1.1‘, #修改这个tag号,可以重新启动爬取 72 "headers" : headers, 73 "timeout" : 100000 74 } 75 76 77 def __init__(self): 78 self.dir_path = DIR_PATH 79 self.tool = Tool() 80 81 82 @every(minutes=24 * 60) # @every修饰器,表示每24小时会执行一次 83 def on_start(self): # 这里设置你要爬取的网页URL(最好是列表的形式,按更新顺序排列),先登录看看是否对应,否则容易出错 84 self.crawl(website_url_initial,validate_cert=False, callback=self.index_page) # self.crawl 告诉 pyspider 抓取指定页面,然后使用 callback 函数对结果进行解析,并调用接下来的index_page 85 # 总结: 86 # 通过 on_start 回调函数,作为爬取的入口点,当点击主面板上的 run 的时候,就是调用这个函数,启动抓取。 87 # self.crawl 告诉调度器,我们需要抓取 ‘某个url‘ 这个页面,然后使用 callback=self.index_page 这个回调函数进行解析。 88 # 所有 return 的内容默认会被捕获到 resultdb 中,可以直接在 WEBUI 上看到(如果结果)。 89 90 91 @config(age=10 * 24 * 60 * 60) #在这表示我们认为 10 天内页面有效,不会再次进行更新抓取 92 #由此,注意,pyspider不会抓取同一个URL两次(永久丢弃),即使修改了代码,对于第一次运行该项目并修改并第二次运行该项目的初学者来说,这是非常常见的。 93 #以上是引述。但是,在实际操作WebUI时,通过单步调试可以很方便地抓取同一个页面。 94 def index_page(self, response): #设置索引页 95 for each in response.doc(detail_page_css).items(): 96 self.crawl(each.attr.href, validate_cert=False,callback=self.detail_page) 97 next = response.doc(next_page_css) 98 self.crawl(next.attr.href,validate_cert=False, connect_timeout = 5000, timeout = 20000,callback=self.index_page) 99 # validate_cert=False 参数,用来解决SSL证书问题,对于以“https”开头的网站,必须添加 100 101 @config(priority=2) 102 def detail_page(self, response): 103 # 使用CSS正则表达式工具修改doc()中的路径,进行页面上的元素的采集 104 title = title_css 105 if (title_css != ‘null‘): 106 title = response.doc(title_css).text() 107 introduction = introduction_css 108 if (introduction_css != ‘null‘): 109 introduction = response.doc(introduction_css).text() 110 time = time_css 111 if (time_css != ‘null‘): 112 time = response.doc(time_css).text() 113 # time = time[10:] #我这里采用了截取字符段的形式,获得真正的时间字符子序列(不通用!!!) 114 datetime_struct = parser.parse(time) 115 time=datetime_struct.strftime(‘%Y-%m-%d‘) # 这里的功能是,将网页代表时间的字符串格式化为%Y-%m-%d(原网页是英文格式) 116 content = content_css 117 if (content_css != ‘null‘): 118 content = response.doc(content_css).text() 119 keywords = keywords_css 120 if (keywords_css != ‘null‘): 121 keywords = response.doc(keywords_css).text() 122 url = response.url 123 picture_url = ‘‘ 124 picture_local_path = ‘‘ 125 file_title = re.sub(‘[\/:*?"<>|]‘,‘-‘,title) 126 imgDir = self.dir_path 127 for imgElem in response.doc(img_css).items(): 128 imgUrl = imgElem.attr.src 129 # imgUrl = imgUrl[:-10] #为了截掉后面多余的字段";width=560",总共10个字符(不通用!!!) 130 if imgUrl and self.tool.get_name(imgUrl) != ‘logo‘: #这个网站每个网页都莫名其妙地爬两个logo图片下来,因此要过滤掉(不通用!!!) 131 picture_url += imgUrl + ‘;‘ #picture_url和picture_local_path都需要滞后于这个过滤操作 132 #获取图片文件后缀 133 extension = self.tool.get_extension(imgUrl) 134 name = self.tool.get_name(imgUrl) 135 #拼接图片名 136 file_name = name + "." + extension 137 picture_local_path += ‘;‘ + file_name 138 self.crawl(imgUrl,callback=self.save_img,save={"file_name":file_name, "imgDir":imgDir},validate_cert=False, connect_timeout = 5000, timeout = 20000) 139 # 这里回调了save_img函数,在单步调试时可以明显看到 140 141 # def detail_page(self, response)作为结果返回一个对象。 142 # 结果将被resultdb默认捕获。 143 # 可以通过覆盖on_result(self, result)自己管理结果的方法。 144 return { # 与你建立的表结构对应。这是python中的字典结构,即“键-值对” 145 "title":title, 146 "introduction":introduction, 147 "time":time, 148 "content":content, 149 "keywords":keywords, 150 "name":project_name, #这里根据你建的表格名修改 151 "source":source_declaration, 152 "url":url, 153 "picture_url":‘null‘ if picture_url == ‘‘ else picture_url, 154 "picture_local_path":‘null‘ if picture_local_path == ‘‘ else picture_local_path 155 } 156 157 158 #保存图片 159 def save_img(self,response): # 可以看到,上面save中保存的内容其实通过response传了过来 160 content = response.content # resp.content返回的是bytes型也就是二进制的数据,resp.text返回的是Unicode型的数据。 161 # 简而言之,如果你想取文本,可以通过r.text。 如果想取图片,文件,则可以通过r.content。 162 file_name = response.save["file_name"] 163 imgDir = response.save["imgDir"] 164 file_path = imgDir + file_name 165 self.tool.save_img(content,imgDir,file_path) 166 167 #数据存储函数:on_result方法 168 def on_result(self,result): 169 if not result or not result[‘title‘]: # 如果没到最后,继续返回数据 170 return 171 sql = SQL() # 覆盖默认方法,使用mysqldb文件中定义的方法,连接数据库 172 sql.insert(project_name,**result) #将结果插入到表格。同理,这里根据你建的表格名修改 173 174 175 #工具类 176 class Tool: 177 #保存图片 178 def save_img(self,content,imgDir,path): 179 if not os.path.exists(imgDir): # os.path.exists(name)判断是否存在文件或目录name 180 os.makedirs(imgDir) # os.makedirs() 方法用于递归创建目录 181 f = open(path,"wb" ) # wb 以只写方式打开 182 f.write(content) # 写入文件 183 f.close() 184 185 #获取url后缀名 186 def get_extension(self,url): 187 extension = url.split(".")[-1] 188 return extension 189 190 #获取图片名 191 def get_name(self,url): 192 name=url.split("/")[-1].split(".")[0] 193 return name
7.forcompositesworld(复合材料世界)基于JEC通用化代码模板_改进
1 #!/usr/bin/env python 2 # -*- encoding: utf-8 -*- 3 # Created on 2018-03-19 22:26:12 4 # Project: Model 5 #问题: 6 #1. ValueError(u‘String does not contain a date)。time的抓取规则仍待改善。对于特别难分离的日期,需要更先进的手段。 ---已解决,注意首先要选择合适、准确、无歧义的CSS表达式。再进行时间格式的处理!或者选取更合适的日期项,如在首页中选择。 7 #2. 仍然有少量OpenSSL connet SSL_ERROR_SYSCALL型的错误。 8 9 10 #**********************************************************************************----------~~~~~~~~\ 11 #伪宏控制__范式编程 12 #------(理论上)你只需要在这里[正确]填入所有信息,整个程序即可运行!【只适用于单一index的爬取。多重分类页面,或者需要对采集的数据做进一步规范化,则必须在后面相应地方改进】 13 project_name = "compositesworld" #你的项目 的名称 14 website_url_initial = ‘https://www.compositesworld.com/news/list‘ #你爬取的初始网页(index页) 的地址 15 detail_page_css = ‘.headline > a‘ #新闻页面链接 的CSS表达式 16 next_page_css = ‘a[aria-label="Next"]‘ #下一页链接 的CSS表达式 17 title_css = ‘.content-headline‘ #新闻标题 的CSS表达式 18 introduction_css = ‘.col-sm-12 > h1‘ #新闻简介 的CSS表达式 19 time_css = ‘.clearfix span[property="dc:created"]‘ #发布时间 的CSS表达式 20 content_css = ‘#short > div > div > p‘ #新闻内容 的CSS表达式 21 img_css = ‘picture > img‘ #新闻图片 的CSS表达式 22 keywords_css = ‘null‘ #关键词,一般页面中无,因此默认为空。#!【重要:如果其他的 *_css 在网页中也找不到对应项的话,可以填‘null‘,程序将自动返回空值】 23 source_declaration = "原创" #原创声明,一般不改动 24 #**********************************************************************************-----------~~~~~~~/ 25 26 from pyspider.libs.base_handler import * #这个库中定义了爬取的各种控制函数和方法 27 import re #re就是regular expression,即正则表达式。正则表达式(通项公式)是用来简洁表达一组字符串的表达式。优势是简洁,一行胜千言。这个库主要用于字符串匹配。 28 from pyspider.database.mysql.mysqldb import SQL 29 from pyspider.database.mysql.mysqldb_new import SQL as SQL_new 30 import sys #用于接下来修改编码格式 31 import os #OS库提供了使用各种操作系统功能的接口 32 import time as ti # 用于延时控制 33 from dateutil import parser #日期处理库,parser子库是根据字符串解析成datetime 34 35 #根据项目名称,自动创建表 36 sql_new = SQL_new() 37 sql_new.create_table(project_name) 38 39 40 #图片存放目录【在当前目录自动创建项目子目录,分类各项目的爬取内容。可实现多项目的同时爬取,而内容分开】 41 path_for_project = "./"+project_name+"/" # ./ 的意思是:当前目录(登录pyspider时) 42 if not os.path.exists(path_for_project): 43 os.makedirs(path_for_project) 44 DIR_PATH = path_for_project 45 else: 46 DIR_PATH = path_for_project 47 #注意哦,“data”文件夹是pyspider启动时自动生成的,其中的db文件是用来默认储存捕获的数据的。但是,我们已经实现了on_result方法把数据传给了Mysql,所以这data文件夹是不起作用的,因此可以忽略。 48 49 #编码转换 50 reload(sys) #Python运行的时候首先加载了site.py,在site.py文件里有这么一段代码: 51 # if hasattr(sys, "setdefaultencoding"): 52 # del sys.setdefaultencoding 53 #可以看出,在sys加载后,setdefaultencoding方法被删除了,所以我们要通过重新导入sys来设置系统编码 54 sys.setdefaultencoding(‘utf8‘) #设置默认编码,UTF-8 55 56 57 class Handler(BaseHandler): 58 59 headers= { 60 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 61 "Accept-Encoding":"gzip, deflate, sdch", 62 "Accept-Language":"zh-CN,zh;q=0.8", 63 "Cache-Control":"max-age=0", 64 "Connection":"keep-alive", 65 "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36" 66 } 67 68 crawl_config = { 69 ‘itag‘: ‘v1.1‘, #修改这个tag号,可以重新启动爬取 70 "headers" : headers, 71 "timeout" : 100000 72 } 73 74 75 def __init__(self): 76 self.dir_path = DIR_PATH 77 self.tool = Tool() 78 79 80 @every(minutes=24 * 60) # @every修饰器,表示每24小时会执行一次 81 def on_start(self): # 这里设置你要爬取的网页URL(最好是列表的形式,按更新顺序排列),先登录看看是否对应,否则容易出错 82 self.crawl(website_url_initial,validate_cert=False, callback=self.index_page) # self.crawl 告诉 pyspider 抓取指定页面,然后使用 callback 函数对结果进行解析,并调用接下来的index_page 83 # 总结: 84 # 通过 on_start 回调函数,作为爬取的入口点,当点击主面板上的 run 的时候,就是调用这个函数,启动抓取。 85 # self.crawl 告诉调度器,我们需要抓取 ‘某个url‘ 这个页面,然后使用 callback=self.index_page 这个回调函数进行解析。 86 # 所有 return 的内容默认会被捕获到 resultdb 中,可以直接在 WEBUI 上看到(如果结果)。 87 88 89 @config(age=10 * 24 * 60 * 60) #在这表示我们认为 10 天内页面有效,不会再次进行更新抓取 90 #由此,注意,pyspider不会抓取同一个URL两次(永久丢弃),即使修改了代码,对于第一次运行该项目并修改并第二次运行该项目的初学者来说,这是非常常见的。 91 #以上是引述。但是,在实际操作WebUI时,通过单步调试可以很方便地抓取同一个页面。 92 def index_page(self, response): #设置索引页 93 for each in response.doc(detail_page_css).items(): 94 self.crawl(each.attr.href, validate_cert=False,callback=self.detail_page) 95 next = response.doc(next_page_css) 96 self.crawl(next.attr.href,validate_cert=False, connect_timeout = 5000, timeout = 20000,callback=self.index_page) 97 # validate_cert=False 参数,用来解决SSL证书问题,对于以“https”开头的网站,必须添加 98 99 @config(priority=2) 100 def detail_page(self, response): 101 # 使用CSS正则表达式工具修改doc()中的路径,进行页面上的元素的采集 102 title = title_css 103 if (title_css != ‘null‘): 104 title = response.doc(title_css).text() 105 introduction = introduction_css 106 if (introduction_css != ‘null‘): 107 introduction = response.doc(introduction_css).text() 108 time = time_css #以下都是在改日期判断 109 if (time_css != ‘null‘): 110 time = response.doc(time_css).text() 111 time.strip() #先作去空格处理 112 time = time[10:] #我这里采用了截取字符段的形式,获得真正的时间字符子序列(不通用!!!) 113 datetime_struct = parser.parse(time) 114 time=datetime_struct.strftime(‘%Y-%m-%d‘) # 这里的功能是,将网页代表时间的字符串格式化为%Y-%m-%d(原网页是英文格式) 115 content = content_css 116 if (content_css != ‘null‘): 117 content = response.doc(content_css).text() 118 keywords = keywords_css 119 if (keywords_css != ‘null‘): 120 keywords = response.doc(keywords_css).text() 121 url = response.url 122 picture_url = ‘‘ 123 picture_local_path = ‘‘ 124 file_title = re.sub(‘[\/:*?"<>|]‘,‘-‘,title) 125 imgDir = self.dir_path 126 for imgElem in response.doc(img_css).items(): 127 imgUrl = imgElem.attr.src 128 imgUrl = imgUrl[:-10] #为了截掉后面多余的字段";width=560",总共10个字符(不通用!!!) 129 if imgUrl: 130 picture_url += imgUrl + ‘;‘ #picture_url和picture_local_path都需要滞后于这个过滤操作 131 #获取图片文件后缀 132 extension = self.tool.get_extension(imgUrl) 133 name = self.tool.get_name(imgUrl) 134 #拼接图片名 135 file_name = name + "." + extension 136 picture_local_path += ‘;‘ + file_name 137 self.crawl(imgUrl,callback=self.save_img,save={"file_name":file_name, "imgDir":imgDir},validate_cert=False, connect_timeout = 5000, timeout = 20000) 138 # 这里回调了save_img函数,在单步调试时可以明显看到 139 140 # def detail_page(self, response)作为结果返回一个对象。 141 # 结果将被resultdb默认捕获。 142 # 可以通过覆盖on_result(self, result)自己管理结果的方法。 143 return { # 与你建立的表结构对应。这是python中的字典结构,即“键-值对” 144 "title":title, 145 "introduction":introduction, 146 "time":time, 147 "content":content, 148 "keywords":keywords, 149 "name":project_name, #这里根据你建的表格名修改 150 "source":source_declaration, 151 "url":url, 152 "picture_url":‘null‘ if picture_url == ‘‘ else picture_url, 153 "picture_local_path":‘null‘ if picture_local_path == ‘‘ else picture_local_path 154 } 155 156 157 #保存图片 158 def save_img(self,response): # 可以看到,上面save中保存的内容其实通过response传了过来 159 content = response.content # resp.content返回的是bytes型也就是二进制的数据,resp.text返回的是Unicode型的数据。 160 # 简而言之,如果你想取文本,可以通过r.text。 如果想取图片,文件,则可以通过r.content。 161 file_name = response.save["file_name"] 162 imgDir = response.save["imgDir"] 163 file_path = imgDir + file_name 164 self.tool.save_img(content,imgDir,file_path) 165 166 #数据存储函数:on_result方法 167 def on_result(self,result): 168 if not result or not result[‘title‘]: # 如果没到最后,继续返回数据 169 return 170 sql = SQL() # 覆盖默认方法,使用mysqldb文件中定义的方法,连接数据库 171 sql.insert(project_name,**result) #将结果插入到表格。同理,这里根据你建的表格名修改 172 173 174 #工具类 175 class Tool: 176 #保存图片 177 def save_img(self,content,imgDir,path): 178 if not os.path.exists(imgDir): # os.path.exists(name)判断是否存在文件或目录name 179 os.makedirs(imgDir) # os.makedirs() 方法用于递归创建目录 180 f = open(path,"wb" ) # wb 以只写方式打开 181 f.write(content) # 写入文件 182 f.close() 183 184 #获取url后缀名 185 def get_extension(self,url): 186 extension = url.split(".")[-1] 187 return extension 188 189 #获取图片名 190 def get_name(self,url): 191 name=url.split("/")[-1].split(".")[0] 192 return name
8.testpro通过调用MySQLnew实现自动创建列表_demo
1 from pyspider.database.mysql.mysqldb_new import SQL 2 3 sql = SQL() #定义一个SQL对象 4 sql.create_table("test_for_auto_table_maker") #用这个对象的create_table方法创建表格,表名为"test_for_auto_table_maker"
9.mysqldb_new(库)
1 #!/usr/bin/env python 2 # -*- encoding: utf-8 -*- 3 #【备注:使用该改进方法可能需要安装的库:sqlalchemy,mysql-connector。均可用pip install快速安装】 4 5 6 from six import itervalues 7 import MySQLdb 8 from sqlalchemy import * 9 from sqlalchemy.orm import * 10 from sqlalchemy.databases import mysql 11 #from sqlalchemy.ext.declarative import declarative_base 12 13 #利用MySQLdb来建立一个名字是变量的表实在太困难了 14 #因此采用了另一个库:sqlalchemy 15 16 class SQL(): 17 def __init__(self): 18 #数据库初始化 19 #数据库连接相关信息(全局化处理)【要实现自动创建表格,必须注意调节create_table中的连接参数信息】 20 hosts = ‘localhost‘ 21 username = ‘root‘ 22 password = ‘233333‘ 23 database = ‘pyspider‘ 24 charsets = ‘utf8‘ 25 port_number = 3307 26 self.connection = False 27 try: 28 self.conn = MySQLdb.connect(host = hosts,user = username,passwd = password,db = database,charset = charsets, port = port_number) 29 self.cursor = self.conn.cursor() 30 self.cursor.execute("set names "+charsets) 31 self.connection = True 32 except Exception,e: 33 print "Cannot Connect To Mysql!/n",e 34 35 def escape(self,string): 36 return ‘%s‘ % string 37 #插入数据到数据库 38 def insert(self,tablename=None,**values): 39 40 if self.connection: 41 tablename = self.escape(tablename) 42 if values: 43 _keys = ",".join(self.escape(k) for k in values) 44 _values = ",".join([‘%s‘,]*len(values)) 45 sql_query = "insert into %s (%s) values (%s)" % (tablename,_keys,_values) 46 else: 47 sql_query = "replace into %s default values" % tablename 48 try: 49 if values: 50 self.cursor.execute(sql_query,list(itervalues(values))) 51 else: 52 self.cursor.execute(sql_query) 53 self.conn.commit() 54 return True 55 except Exception,e: 56 print "An Error Occured: ",e 57 return False 58 # 用于建立表格,可能之后需要加强try-except机制 59 # 【经测试,该方法不会覆盖掉已经创建过的表格】 60 def create_table(self,project_name): 61 #定义引擎 62 engine = create_engine(‘mysql+mysqlconnector://root:fdzxks@localhost:3307/pyspider‘) # 这里的引擎与上面的连接参数要相应一致 63 #绑定元信息 64 metadata = MetaData(engine) 65 #创建表格,初始化数据库 66 user = Table(project_name, metadata, 67 Column(‘title‘, VARCHAR(255)), 68 Column(‘introduction‘, mysql.MSLongText), 69 Column(‘time‘, VARCHAR(255)), 70 Column(‘content‘, mysql.MSLongText), 71 Column(‘keywords‘, VARCHAR(255)), 72 Column(‘name‘, VARCHAR(255)), 73 Column(‘source‘, VARCHAR(255)), 74 Column(‘url‘, VARCHAR(255)), 75 Column(‘picture_url‘, mysql.MSLongText), 76 Column(‘picture_local_path‘, mysql.MSLongText), 77 ) 78 #http://blog.csdn.net/FeiSan/article/details/1887677。教程:SQLAlchemy下定义MySQL特有的字段类型。 79 #创建数据表,如果数据表存在则忽视 80 metadata.create_all(engine) 81 #获取数据库链接,以备后面使用 82 conn = engine.connect()
原文:https://www.cnblogs.com/zjbh/p/11435233.html