当前位置: 首页 > 后端技术 > Python

爬取

时间:2023-03-26 19:18:51 Python

在一个scrapy学习的爬虫练习平台:https://scrape.center/,目前已经爬取了前十个比较简单的网站,感谢平台作者提供练习平台。在开始爬取之前,首先要搭建好环境。Pycharm新建项目learnscrapy及对应的虚拟环境,安装Scrapy和PyMysql,执行scrapystartprojectlearnscrapy新建scrapy项目。具体环境搭建步骤不再赘述,该项目也在Github上开源,地址在这里。开始前的准备由于新建的项目都是默认设置,所以在开始分析对应的网站之前,先做一些设置,方便后续的抓取。要设置机器人规则,请在settings.py文件中将ROBOTSTXT_OBEY的值更改为False。其实这个目前不需要设置,因为目标网站是没有robot文件的,但是为了防止少了数据被莫名其妙抓到,还是养成习惯比较好。设置日志级别。默认的日志级别是DEBUG,会打印出所有的请求和状态。大规模爬取的时候,日志又多又乱。在settings.py文件中添加以下设置,过滤掉一些日志。importloggingLOG_LEVEL=logging.INFO设置下载延迟为了不对目标网站造成太大影响,稍微降低下载延迟,默认下载延迟为0,取消DOWNLOAD_DELAY的注释,设置为0.1。关闭Telnet控制台。目前基本不用,关掉吧。将TELNETCONSOLE_ENABLED的值设置为False。更改默认请求头为了让我们的请求更像一个普通的请求,我们需要设置默认请求头来防止被禁止。DEFAULT_REQUEST_HEADERS={'Accept':'text/html,application/xhtml+xml,application/xml,application/json;q=0.9,*/*;q=0.8','accept-encoding':'gzip,deflate,br','accept-language':'zh-CN,zh;q=0.9','cache-control':'no-cache','User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,''likeGecko)Chrome/86.0.4240.75Safari/537.36'}管道和中间件会在使用时开启,准备工作到此结束。为数据库准备一个MySQLdocker容器,设置好数据库账号和密码,新建一个数据库,名称为test。运行项目根目录下的test.sql文件,会生成三张表,下面爬取的时候会用到。开始爬取ssr1ssr1说明如下:ssr1:电影数据网站,无反爬,数据通过服务端渲染,适合基础爬行练习。既然是服务端渲染,数据肯定存在于HTML源码中,直接从源码中抓取数据即可。在spiders文件夹新建一个ssr1.py文件,写入如下代码:center/page/{a}'forainrange(1,11)]forurlinurls:yieldscrapy.Request(url=url,callback=self.parse)defparse(self,response,**kwargs):pass的两个方法就是我们需要实现的。start_requests方法存储起始URL,通过yield向下载器发送请求,并通过默认的parse方法处理返回的数据。在解析数据之前,还有一些事情要做。设置采集数据的字段,打开itempipeline,指定谁来处理数据,将修改后的设置写入setting.py文件。需要为要收集的数据创建一个新字段。添加以下内容到items.py文件中:)country=scrapy.Field()time=scrapy.Field()date=scrapy.Field()director=scrapy.Field()打开itempipeline,在settings.py文件中将ITEM_PIPELINES取消注释,修改内容为:ITEM_PIPELINES={'learnscrapy.pipelines.SSR1Pipeline':300,}在pipelines.py文件中添加如下内容:ssr1.py中的html源码,通过xpath获取对应数据,通过yield请求请求下一页,使用meta参数传递item数据,callback参数指定回调函数。完整代码如下:importscrapyfromscrapyimportRequestfromlearnscrapy.itemsimportSSR1ScrapyItemclassSSR1(scrapy.Spider):name='ssr1'defstart_requests(self):urls=[f'https://ssr1.scrape.center/page/{a}'forainrange(1,11)]forurlinurls:yieldscrapy.Request(url=url,callback=self.parse)defparse(self,response,**kwargs):result=response.xpath('//div[@class="el-carditemm-tis-hover-shadow"]')对于结果:item=SSR1ScrapyItem()item['title']=a.xpath('.//h2[@class="m-b-sm"]/text()').get()item['fraction']=a.xpath('.//p[@class="scorem-t-mdm-b-n-sm"]/text()').get().strip()item['country']=a.xpath('.//div[@class="m-v-sminfo"]/span[1]/text()').get()item['time']=a.xpath('.//div[@class="m-v-sminfo"]/span[3]/text()').get()item['date']=a.xpath('.//div[@class="m-v-sminfo"][2]/span/text()').get()url=a.xpath('.//a[@class="name"]/@href').get()yieldRequest(url=response.urljoin(url),callback=self.parse_person,meta={'item':item})defparse_person(self,response):item=response.meta['item']item['director']=response.xpath('//div[@class="directorsel-row"]//p[@class="nametext-centerm-b-nonem-t-xs"]/text()').get()yielditem然后在项目中新建启动文件main.py路径,一般情况下应该使用命令行来启动爬虫。为了方便调试,我们使用Pycharm启动,在main.py文件中写入如下内容:fromscrapy.cmdlineimportexecuteif__name__=='__main__':execute(['scrapy','crawl','ssr1'])执行它,数据应该以字典的形式打印出来,因为我们是在item管道中输出的,还没有写入数据库。接下来在pipelines.py文件中添加将数据输入库的代码,完整代码如下:classSSR1Pipeline:def__init__(self):self.conn:pymysql.connectself.cur:pymysql.cursors.Cursorself.queue=[]self.count=0defopen_spider(self,spider):self.conn=pymysql.connect(host='192.168.233.128',user='root',password='123456',db='test',port=3306,charset='utf8')self.cur=self.conn.cursor()defclose_spider(self,spider):如果len(self.queue)>0:self.insert_database()self.cur.close()self.conn.close()definsert_database(self):sql="insertintossr1(country,date,director,fraction,time,title)values(%s,%s,%s,%s,%s,%s)"self.cur.executemany(sql,self.queue)self.queue.clear()self.conn.commit()defprocess_item(self,item,spider):self.queue.append((item['country'],item['日期'],item['导演'],item['分数'],item['time'],item['title']))iflen(self.queue)>30:self.insert_database()returnitem重新运行爬虫,应该写入完整的100条数据提交完整代码到数据库,见https://github.com/libra146/learnscrapy/tree/ssr1ssr2ssr2说明如下:电影数据网站,无反爬,无HTTPS证书,适用于HTTPS证书验证。Scrapy默认不验证HTTPS证书,只是发出警告,所以爬取规则应该和ssr1一致,但是ssr2的后端服务可能有问题。我这里一直报504错误,浏览器打不开。我暂时无法测试规则。有效吗。完整代码提交见https://github.com/libra146/learnscrapy/tree/ssr2ssr3ssr3说明如下:电影数据网站,无反爬,带HTTPBasicAuthentication,适用于HTTP认证情况,用户名和密码都是admin。由于本站有BasicAuthentication,所以需要在请求头中添加认证信息,使用scrapy中的下载中间件来实现。其他代码和上面两个一样,不同的是ssr3通过custom_settings指定了一个自定义的下载中间件。classSSR3Spider(scrapy.Spider):name="ssr3"#覆盖全局设置中的设置,使用自定义的下载中间件custom_settings={'DOWNLOADER_MIDDLEWARES':{'learnscrapy.middlewares.SSR3DownloaderMiddleware}要旸4霌':在middlewares.py中添加如下代码:classSSR3DownloaderMiddleware:#并不是所有的方法都需要定义。如果未定义方法,#scrapy就好像下载器中间件不修改#传递的对象一样。@classmethoddeffrom_crawler(cls,crawler):#这个方法被Scrapy用来创建你的爬虫。s=cls()crawler.signals.connect(s.spider_opened,signal=signals.spider_opened)returnsdefprocess_request(self,request,spider):#为通过下载器的每个请求调用#中间件。#必须:#-returnNone:继续处理这个请求#-或者返回一个Response对象#-或者返回一个Request对象#-或引发IgnoreRequest:process_exception()#安装的下载器中间件的方法将被调用#添加验证信息request.headers.update({'authorization':'Basic'+base64.b64encode('admin:admin'.encode()).decode()})returnNonedefprocess_response(self,request,response,spider):#调用下载器返回的响应。#必须之一;#-返回一个Response对象#-返回一个Request对象#-或引发IgnoreRequest返回响应defprocess_exception(self,request,exception,spider):#当下载处理程序或process_request()#(来自其他下载器中间件)引发时调用一个例外。#必须:#-returnNone:继续处理这个异常#-返回一个Response对象:stopsprocess_exception()chain#-返回一个Request对象:stopsprocess_exception()chainpassdefsspider_opened(self,spider):spider.logger.info('Spideropened:%s'%spider.name)发送请求前在请求头中添加认证信息即可,但是添加认证信息后服务器仍然返回504,猜测是因为在nginx中配置了HTTPBasicAuthentication,导致后台服务器还处于离线状态,导致出现这种情况。完整代码提交见https://github.com/libra146/learnscrapy/tree/ssr3ssr4ssr4说明如下:电影数据网站,无反爬,每次响应加5秒延时,适合测试慢网站抓取或做抓取进行速度测试以减少网络速度干扰。对于scrapy,可以使用ssr4来测试爬取速度,排除网速干扰。爬取规则没有区别,只是时间稍长一点。代码基本没变。完整的代码提交见https://github.com/libra146/learnscrapy/tree/ssr4总结以上就是全部ssr爬取分析和代码。对于这个没有反爬措施,不限制爬取速度的简单网站比较简单,有助于理解scrapy的写法和框架。参考链接https://docs.scrapy.org/en/latest/index.html