概述pymysql是一个纯Python实现的MySQL客户端操作库。Python–以下之一:CPython>=2.7或>=3.5MySQLServer–以下之一:MySQL>=5.5MariaDB>=5.5通用使用步骤importpymysql#连接MySQLconn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123456",database="bigdataboy",charset='utf8')#创建光标cur=conn.cursor()#SQL语句sql=""#执行SQL语句r=cur.execute(sql)#这一步提交只有在修改,增加,删除时需要,查询时不需要。conn.commit()#commit作用是:更新状态到数据库#关闭连接conn.close()创表importpymysqlconn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123456",database="bigdataboy",charset='utf8')cur=conn.cursor()sql="""createtablebigdata(idintprimarykeyauto_increment,namevarchar(255)notnull,phoneint)charset="utf8";"""r=cur.execute(sql)#创建成功返回0,失败返回1conn.commit()conn.close()插入数据插入一条数据importpymysqlconn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123456",database="bigdataboy",charset='utf8')cur=conn.cursor()sql="insertintobigdatavalues(null,'bigdataboy',123456789)"r=cur.execute(sql)#插入成功返回1,影响的行数conn.commit()conn.close()插入多条数据使用如下executemany()方法可以预防SQL注入攻击。importpymysqlconn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123456",database="bigdataboy",charset='utf8')cur=conn.cursor()#需要插入数据用%s代替sql="insertintobigdatavalues(null,%s,%s)"data=[("Bob",123456),("Block",123456),("Bigdataboy",123456789)]#参数1是SQL语句,参数2是数据列表(需要循环)。r=cur.executemany(sql,data)#返回添加的行数conn.commit()conn.close()查询数据查询结果有4中返回格式:Cursor:默认,元组类型DictCursor:字典类型SSCursor:无缓冲元组类型SSDictCursor:无缓冲字典类型无缓冲游标类型,适用于数据量很大,一次性返回太慢,或者服务端带宽较小默认元组返回结果cur=conn.cursor()sql="select*frombigdata;"r=cur.execute(sql)#返回查询到的数据条数print(cur.fetchall())#提取所有查询到的结果conn.close()-----------------------------((1,'bigdataboy',123456789),(2,'bigdataboy',123456789),(3,'bigdata',1234567),(4,'Bob',123456))字段返回类型importpymysqlconn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123456",database="bigdataboy",charset='utf8')#指定DictCursor类cur=conn.cursor(cursor=pymysql.cursors.DictCursor)sql="select*frombigdata;"r=cur.execute(sql)print(cur.fetchall())#提取所有查询到的结果conn.close()-------------------------------[{'id':1,'name':'bigdataboy','phone':123456789},{'id':2,'name':'bigdataboy','phone':123456789},{'id':3,'name':'bigdata','phone':1234567}]返回结果的提取方法方法作用fetchall()取出全部的数据,可以返回一个结果集fetchmany(size)取出一定数量的数据fetchone()取出一条数据
概述在项目中,我们可能遇到有定时任务的需求。定时执行任务:例如每天早上8:00定时推送早报。间隔执行任务:比如:爬虫间隔多少时间去爬取一次。模块简介它是一个轻量级的Python定时任务调度框架。有四种组件,分别是:调度器(scheduler),作业存储(jobstore),触发器(trigger),执行器(executor),这里只介绍触发器(trigger)。同时,它还支持异步执行、后台执行调度任务。触发器APScheduler有三种内建的触发器。date触发器:表示特定时间点触发,只执行一次。interval触发器:固定时间间隔触发。cron触发器:在特定时间周期触发,最强大的触发器,能实现每天固定时间执行功能。date触发器参数:参数说明run_date(datetime或str)作业的运行日期或时间timezone(datetime.tzinfo或str)指定时区fromapscheduler.schedulers.blockingimportBlockingSchedulerfromdatetimeimportdatetimedeffunc():print(datetime.now().strftime("%Y-%m-%d%H:%M:%S"))scheduler=BlockingScheduler()#2020-03-1617:50:00指定时间运行一次scheduler.add_job(func,next_run_time=datetime(2020,3,16,17,50))scheduler.start()interval触发器以下都是可选参数(如果不填,就是当前开始间隔一秒执行一次但不会执行太久,会自动停止):参数说明weeks(int)间隔几周days(int)间隔几天hours(int)间隔几小时days(int)间隔几天minutes(int)间隔几分钟seconds(int)间隔多少秒start_date(datetime或str)开始日期end_date(datetime或str)结束日期timezone(datetime.tzinfo或str)时区fromapscheduler.schedulers.blockingimportBlockingSchedulerfromdatetimeimportdatetimedeffunc():print(datetime.now().strftime("%Y-%m-%d%H:%M:%S"))scheduler=BlockingScheduler()#每6秒执行一次scheduler.add_job(func,trigger="interval",seconds=6)scheduler.start()cron触发器在特定时间周期性地触发,和Linuxcrontab格式兼容。它是功能最强大的触发器。参数:header1header2year(int或str)年,4位数字month(int或str)月(范围1-12)day(int或str)日(范围1-31week(int或str)周(范围1-7)day_of_week(int或str)周内第几天或者星期几(范围0-6或者mon,tue,wed,thu,fri,sat,sun)hour(int或str)时(范围0-23)minute(int或str)分(范围0-59)second(int或str)秒(范围0-59)start_date(datetime或str)最早开始日期(包含)end_date(datetime或str)最晚结束时间(包含)timezone(datetime.tzinfo或str)指定时区fromapscheduler.schedulers.blockingimportBlockingSchedulerfromdatetimeimportdatetimedeffunc():print(datetime.now().strftime("%Y-%m-%d%H:%M:%S"))scheduler=BlockingScheduler()#在1到3月和7到9月的8到12和16到20的30分执行scheduler.add_job(func,trigger='cron',month='1-3,7-9',hour="8-12,16-20",minute='30')scheduler.start()
爬虫目标通过微博话题获取发帖的信息与用户基本信息,数据可用于该话题的用户分析。爬取字段:账号id号、昵称、关注数、粉丝数、微博数、个性签名、账号类型、等级、简介、使用设备所用到模块:requests、lxml、re说明:无登录爬取微博用户数据,实现自动获取Cookie和Cookie失效自动更新,还有其他技巧,自己看。爬虫结构classWeiBoSpider():def__init__(self):#起始地址self.url="https://s.weibo.com/weibo?q=%23%E8%94%A1%E5%BE%90%E5%9D%A4%E7%82%B9%E8%AF%84%23&Refer=top"#cookieself.cookie=self.get_cookie()#获取所有数据defget_data(self):pass#通过id获取用户信息defget_user_data(self,user_id):pass#获取&更新Cookiedefget_cookie(self):passif__name__=='__main__':wbs=WeiBoSpider()wbs.get_data()获取所有数据defget_data(self):r=requests.get(url=self.url)html=etree.HTML(r.text)#接信息网页userdatas_list=html.xpath('//div[@id="pl_feedlist_index"]/div/div[@action-type="feed_list_item"]')#获取数据users_list=list()foruserdatainuserdatas_list:#昵称nick_name=userdata.xpath('.//div[@class="info"]/div[2]/a/@nick-name')#个人页user_id=re.search(r'/(\d*?)\?',userdata.xpath('.//div[@class="info"]/div[2]/a[1]/@href')[0]).group(1)#账号类型user_type=userdata.xpath('.//div[@class="info"]/div[2]/a[2]/@title')#使用设备equipment=userdata.xpath('.//p[@class="from"]/a[2]/text()')#组合数据data={"nick_name":nick_name,"user_id":user_id,"user_type":user_type,"equipment":equipment,#调用函数获取用户信息"user_data":self.get_user_data(user_id),}print(data)users_list.append(data)returnusers_list通过ID用户信息获取用户信息时,就对Cookie有着严格的要求,但是我们实现了自动化获取Cookie。defget_user_data(self,user_id="2803301701"):user_url="https://weibo.com/u/{}".format(user_id)headers={"Content-Type":"text/html;charset=utf-8","Host":"weibo.com",}r=requests.get(url=user_url,headers=headers,cookies=self.cookie)#判断cookie的有效性ifr.text=="":r=requests.get(url=user_url,headers=headers,cookies=self.get_cookie())#个人签名try:user_sign=re.search(r"简介:(.*?)<\\/span>",r.text).group(1).replace("\\t","").strip()exceptAttributeError:user_sign=""#关注concern=re.search(r'">(\d*?)<\\/strong><spanclass=\\"S_txt2\\">关注',r.text).group(1)#粉丝fans=re.search(r'">(\d*?)<\\/strong><spanclass=\\"S_txt2\\">粉丝<\\/span>',r.text).group(1)#微博数量weibo_count=re.search(r'">(\d*?)<\\/strong><spanclass=\\"S_txt2\\">微博',r.text).group(1)return{"user_sign":user_sign,"concern":concern,"fans":fans,"weibo_count":weibo_count}Cookie获取&更新在爬取微博用户数据遇到困难的朋友可以参考以下。defget_cookie(self):s=requests.session()#获取第一个Cookies.get("https://passport.weibo.com/visitor/visitor")#获取tid参数tid_=s.post(url="https://passport.weibo.com/visitor/genvisitor",data={"cb":"gen_callback","fp":{}})tid=re.search(r'{"tid":"(.+?)"',tid_.text).group(1)#返回需要的所有Cookier=s.get(url="https://passport.weibo.com/visitor/visitor",params={"a":"incarnate","t":tid,"cb":"cross_domain",})cookies=r.cookiestry:cookies["SRT"]exceptKeyError:print("获取cookie失败,真正重新获取")returnself.get_cookie()else:self.cookie=cookiesprint(self.cookie)returncookies运行结果暂没有翻页功能,看后面补充吧!!!
爬虫目标爬取房天下指定地区的所在小区、小区链接、小区地址、户型、总价、单价等使用的模块:requests、lxml、re、json爬虫结构以下结构可以很好的进行多线程或者协程的扩展。参数类classTool():#需要爬取的城市city="成都"#爬取页数page=2#城市列表获取所以城市的URL的方法在文末,这里只截取了一部分city_url={'成都':'https://cd.esf.fang.com','郴州':'https://chenzhou.esf.fang.com'}解析网页获取信息#获取房子的信息defget_fang_infor(url):#信息fang_list=list()#获取网页信息r=requests.get(url=url)r.encoding=r.apparent_encoding#这里的错误处理是在爬取第二页之后,URL需要获取一个参数try:href=re.search(r'//location.href="(.*?)";',r.text).group(1)exceptAttributeError:passelse:r=requests.get(url=href)r.encoding=r.apparent_encoding#解析网页html=etree.HTML(r.text)dl_html=html.xpath('//div[@class="shop_listshop_list_4"]/dl')fordlindl_html:#小区名称house=dl.xpath('.//p[@class="add_shop"]/a/@title')ifhouse==list():continue#小区链接house_url=url+dl.xpath('.//p[@class="add_shop"]/a/@href')[0]#小区地址house_add=dl.xpath('.//p[@class="add_shop"]/span/text()')#户型等去除前后符号house_types=[a.strip()foraindl.xpath('.//p[@class="tel_shop"]/text()')]#总价all_price=dl.xpath('.//dd[@class="price_right"]/span[1]/b/text()')[0]+dl.xpath('.//dd[@class="price_right"]/span/text()')[0]#单价price=dl.xpath('.//dd[@class="price_right"]/span[2]/text()')#组合数据infor={#小区名称"house":house[0],#小区地址"house_add":house_add[0],#小区链接"house_url":house_url,#户型"house_type":house_types[0],#大小"house_size":house_types[1][:-2],#楼层"floor":house_types[2],#方向"direction":house_types[3],#修建日期"xj_date":house_types[4],#总价"all_price":all_price,#单价"price":price[0][:-3]}fang_list.append(infor)returnfang_list获取所有链接返回一个所有链接的list()#获取页数连接defget_pages():url=Tool.city_url[Tool.city]pages_list=[url]fornuminrange(2,Tool.page+1):pages_list.append(url+"/house/i3{}/".format(num))returnpages_list主程序入口if__name__=='__main__':pages_list=get_pages()print(pages_list)#打印链接列表forpageinpages_list:print(page)#当前爬取的链接fang_list=get_fang_infor(page)print(fang_list)获取所有城市的URLdefget_city_url():url="https://esf.fang.com/esfcities.aspx"r=requests.get(url=url,timeout=5)r.encoding=r.apparent_encoding#匹配城市&urlcity_url_lists=json.loads(re.search(r"varcityJson=(.*?),];",r.text).group(1)+"]")#重新组合格式city_url_dic=dict()#{,...}foraincity_url_lists:city_url_dic={**city_url_dic,**{a.get("name"):"https:"+a.get("url")}}print(city_url_dic)
爬虫目标指定日期,爬取人民日报所有版面的新闻简要分析版面链接分析发现一共有20个版面,分别有20个链接,只是每个链接后的数字不同http://paper.people.com.cn/rmrb/html/2020-03/12/nbs.D110000renmrb_01.htm爬虫结构用到模块:requests、BeautifulSoup、gevent构造参数类需要下载其他日期,自行修改就好classTOOL():#年月yyyy-mm格式date="2020-03"#日期day="12"#新闻详情页text_url="http://paper.people.com.cn/rmrb/html/{}/{}/".format(date,day)#版面URL列表@classmethoddefget_urls(cls):urls=list()#链接列表fornuminrange(1,20):#10以下数字补0if1<=num<10:num="0"+str(num)urls.append("http://paper.people.com.cn/rmrb/html/{}/{}/nbs.D110000renmrb_{}.htm".format(cls.date,cls.day,num))returnurls获取新闻页链接获取一个版面的新闻链接defget_layout_url(url):"""返回值:[{"layout":layout,"href":href},{"layout":layout,"href":href},...]"""print(url)r=requests.get(url=url)r.encoding=r.apparent_encoding#解析网页获取版面名称、文章链接soup=BeautifulSoup(r.text,"html.parser")list_l_soup=soup.find(name="div",attrs={"class":"list_l"})#获取版面名layout=list_l_soup.find_next(name="div",attrs={"class":"l_t"}).string.strip()print(layout)ul_soup=list_l_soup.find_next(name="div",attrs={"id":"titleList"}).find_next(name="ul")li_soup=ul_soup.find_all(name="li")#返回值列表href_titles=list()forhref_title_taginli_soup:#获取hrefhref=TOOL.text_url+href_title_tag.find(name="a")["href"]print(href)#结果组合href_titles.append({"layout":layout,"href":href})returnhref_titles下载新闻并保存提前创建好rb/目录defdownload(href_titles):forhref_titleinhref_titles:#获取新闻页r=requests.get(url=href_title.get("href"))r.encoding=r.apparent_encoding#解析新闻页soup=BeautifulSoup(r.text,"html.parser")soup_text=soup.find(name="div",attrs={"class":"text_c"})#文章标题title=soup_text.h1.stringprint(title)#正文main_sc=soup_text.find_next(name="div",attrs={"id":"ozoom"})#正文里有一段script的注释,对结果有影响,需要替换掉main_sc.find_next(name="script",attrs={"language":"javascript"}).string=""main_text=main_sc.get_text().strip()#写入文件withopen("rb/"+title+".txt","w+",encoding="utf-8")asfile:file.write(main_text)主逻辑if__name__=='__main__':#通过for循环获取所有新闻链接,组成列表href_titles=[get_layout_url(url)forurlinTOOL.get_urls()]#添加协程队列并下载layout_url_list=[gevent.spawn(download,href_title)forhref_titleinhref_titles]gevent.joinall(layout_url_list)
爬虫目标下载必应搜索的背景壁纸使用模块:requests、gevent接口(get):https://cn.bing.com/HPImageArchive.aspx主要参数"format":"js","idx":"0","n":"20",#壁纸数量,壁纸本身没几张,大了也没有爬虫主体获取壁纸连接返回包含壁纸URL和hash码的字典的列表defget_url_title():url="https://cn.bing.com/HPImageArchive.aspx"params={"format":"js","idx":"0","n":"20",#壁纸数量,壁纸本身没几张,大了也没有}r=requests.get(url=url,params=params).json()#存url和hsh的列表url_title_list=list()#解析jsonforimgdatainr.get("images"):hsh=imgdata.get("hsh")imgurl="https://cn.bing.com"+imgdata.get("url")#print(url,copyright)url_title_list.append({"url":imgurl,"hsh":hsh})returnurl_title_list下载并保存壁纸提前创建imgs/文件夹defdownload(url_title):#下载壁纸img_content=requests.get(url_title.get("url")).content#保存文件print(url_title.get("hsh"))withopen("imgs/"+url_title.get("hsh")+".jpg","wb+")asfile:file.write(img_content)主逻辑if__name__=='__main__':url_titles=get_url_title()#协程队列spawnList=[gevent.spawn(download,url_title)forurl_titleinurl_titles]#等待协程队列执行gevent.joinall(spawnList)
何为下载中间件下载器中间件是Scrapy的请求/响应处理的类。这是一个轻量级的低级系统,用于全局更改Scrapy的请求和响应。使用要激活下载程序中间件组件,请将其添加到DOWNLOADER_MIDDLEWARES设置中,这是一个dict,其键为中间件类路径,其值为中间件顺序(权重)#Enableordisabledownloadermiddlewares#Seehttps://docs.scrapy.org/en/latest/topics/downloader-middleware.htmlDOWNLOADER_MIDDLEWARES={'lagouApp.middlewares.LagouappDownloaderMiddleware':543,}将该DOWNLOADER_MIDDLEWARES设置与DOWNLOADER_MIDDLEWARES_BASEScrapy中定义的设置合并(而不是被覆盖),然后按顺序进行排序,以获取启用的中间件的最终排序列表,请求会按照小到大执行,响应会按照大到小执行,其各个中间件权重大小的决定,可参照DOWNLOADER_MIDDLEWARES_BASE设置。如果要禁某个中间件把它设置为None就好。内置下载中间件CookiesMiddleware属于scrapy.downloadermiddlewares.cookies.CookiesMiddleware类使用此中间件,可以处理需要cookie的站点,例如使用会话的站点。它会跟踪Web服务器发送的cookie,并像网络浏览器一样,将其发送回后续请求(来自该蜘蛛)。注意meta.get(‘cookiejar’)不是“粘性”的您需要在后续请求中继续传递它defparse_page(self,response):#dosomeprocessingreturnscrapy.Request("https://bigdataboy.cn",meta={'cookiejar':response.meta['cookiejar']},callback=self.parse_other_page)相关设置COOKIES_ENABLED默认启用cookies#Disablecookies(enabledbydefault)是否启用cookies#COOKIES_ENABLED=TrueCOOKIES_DEBUG如果启用,Scrapy将记录请求中发送的所有cookie(即Cookie标头)和响应中接收的所有cookie(即Set-Cookie标头)。COOKIES_DEBUG=False开启效果2020-01-1420:20:26[scrapy.downloadermiddlewares.cookies]DEBUG:Receivedcookiesfrom:<200https://bigdataboy.cn>Set-Cookie:JSESSIONID=ABAAABAAAEEAAII73F8A39DC3BF1352400CBB34ABA2AB47;Path=/;HttpOnlySet-Cookie:SEARCH_ID=11c20adceed742cd9ed906fe2e0c47ad;Version=1;Max-Age=86400;Expires=Wed,15-Jan-202012:20:28GMT;Path=/Set-Cookie:user_trace_token=20200114202028-23b9b484-6bec-4761-a4ec-4a08c2bae9e9;Max-Age=31536000;Path=/;Domain=.lagou.com;2020-01-1420:20:26[scrapy.core.engine]DEBUG:Crawled(200)<GEThttps://bigdataboy.cn>(referer:None)UserAgentMiddleware属于scrapy.downloadermiddlewares.useragent.UserAgentMiddleware类允许蜘蛛覆盖默认用户代理的中间件。为了使Spider可以覆盖默认用户代理,user_agent必须设置其属性。DefaultHeadersMiddleware属于scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware类该中间件会把setting中指定的所有默认请求标头加入HttpProxyMiddleware属于scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware类该中间件通过设置Request.meta的proxy值来设置代理池和设置Request.headers里的认证头部(Proxy-Authorization)DownloadTimeoutMiddleware属于scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware类该中间件会获取DOWNLOAD_TIMEOUT的值给蜘蛛设置下载的超时时间。还可以给每个Request.meta设置download_timeout属性,单独设置超时时间。HttpAuthMiddleware属于scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware类该中间件使用基本访问身份验证(也称为HTTP身份验证)对从某些蜘蛛生成的所有请求进行身份验证。要启用某些蜘蛛网的HTTP身份验证,请设置这些蜘蛛网的http_user和http_pass属性。fromscrapy.spidersimportCrawlSpiderclassSomeIntranetSiteSpider(CrawlSpider):http_user='someuser'http_pass='somepass'name='bigdataboy.cn'#..restofthespidercodeomitted...HttpCacheMiddleware属于scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware类该中间件为所有HTTP请求和响应提供了低级缓存。它必须与缓存存储后端以及缓存策略结合使用HttpCompressionMiddleware属于scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware类该中间件允许从网站发送/接收压缩(gzip,deflate)流量。如果安装了brotlipy,此中间件还支持解码brotli压缩的响应。相关设置COMPRESSION_ENABLEDCOMPRESSION_ENABLED=TrueRedirectMiddleware属于scrapy.downloadermiddlewares.redirect.RedirectMiddleware类该中间件根据响应状态处理请求的重定向。可以在Request.meta的redirect_urls中找到请求通过的URL(在重定向时)。还可以在Request.meta的redirect_reasons中找到每个重定向的背后原因。例如:。[301,302,307,'metarefresh']相关设置REDIRECT_ENABLED#启用重定向中间件REDIRECT_ENABLED=TrueREDIRECT_MAX_TIMES#单个请求将遵循的最大重定向数。REDIRECT_MAX_TIMES=20RetryMiddleware属于scrapy.downloadermiddlewares.retry.RetryMiddleware类中间件,用于重试失败的请求,这些请求可能是由临时问题(例如连接超时或HTTP500错误)引起的。蜘蛛完成对所有常规(非失败)页面的爬网之后,将在抓取过程中收集失败的页面,并在最后进行重新请求。相关设置RETRY_ENABLED#启用“重试”中间件。RETRY_ENABLED=TrueRETRY_TIMES#除了首次下载外,最大重试次数。RETRY_TIMES=2RETRY_HTTP_CODES#重试哪个HTTP响应代码。RETRY_HTTP_CODES=[500,502,503,504,522,524,408,429]DownloaderStats属于scrapy.downloadermiddlewares.stats.DownloaderStats类中间件,用于存储通过它的所有请求,响应和异常的统计信息。要使用此中间件,必须启用该DOWNLOADER_STATS=True(默认开启)。AjaxCrawlMiddleware属于scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware类基于元片段html标签找到“AJAX可抓取”页面变体的中间件。有关更多信息,请参见https://developers.google.com/webmasters/ajax-crawling/docs/getting-started。
DownloaderMiddlewares(下载器中间件)Scarpy的新版本能自动生成下载器中间件,一般不用自己去重写下载器中间件是引擎和下载器之间通信的中间件。在这个中间件中我们可以设置代理、更换请求头等来达到反反爬虫的目的。要写下载器中间件,可以在下载器中实现两个方法..process_request(self,request,spider):这个方法是在请求发送之前会执行process_response(self,request,response,spider),这个方法是数据下载到引擎之前执行process_request(self,request,spider)这个方法是在请求发送之前会执行参数:request:发送请求的request对象。spider:发送请求的spider对象返回值:已经激活中间件,process_response()方法则会在每个response返回时被调用。返回None:Scrapy将继续处理该请求,执行其他中间件中的相应方法,直到合适的下载器处理函数被调用。返回Response对象:Scrapy将不会调用任何其他的process.request方法,将直接返回这个response对象。返回Request对象:不再使用之前的request对象去下载数据,而是根据现在返回的request对象返回数据。如果这个方法中抛出了异常,则会调用process.exception方法。process_response(self,request,response,spider)这个方法是在收到相应时执行参数:request:request对象。response:待处理的response对象。spider:splder对象。返回值:返回Response对象:会将这个新的Response对象传给其他中间件处理。返回Request对象:下载器链被切断,返回的Request会重新被下载器调度请求。如果抛出一个异常,那么调用request的errback方法,如果没有指定这个方法,那么会抛出一个异常。随机请求头请求头网站:http://www.useragentstring.com/pages/useragentstring.php?typ=Browser开启下载中间件#Enableordisabledownloadermiddlewares#Seehttps://docs.scrapy.org/en/latest/topics/downloader-middleware.htmlDOWNLOADER_MIDDLEWARES={'headersApp.middlewares.HeadersappDownloaderMiddleware':543,}设置随机请求头在middlewares.py里编辑DownloaderMiddleware()类classHeadersappDownloaderMiddleware(object):HEADERS=['Mozilla/5.0(iPhone;CPUiPhoneOS11_0likeMacOSX)AppleWebKit/604.1.38(KHTML,likeGecko)Version/11.0Mobile/15A372Safari/604.1','Mozilla/5.0(WindowsNT6.1;WOW64;rv:40.0)Gecko/20100101Firefox/40.1','Mozilla/5.0(WindowsNT6.1;WOW64;Trident/7.0;AS;rv:11.0)likeGecko','Mozilla/5.0(Windows;U;WindowsNT5.1;en-US;rv:1.9.2.21pre)GeckoK-Meleon/1.7.0','Mozilla/4.0(compatible;MSIE6.0;WindowsXP5.1)Lobo/0.98.4','Mozilla/5.0(Windows;U;WindowsNT6.1;en-US;rv:1.9.2.28)Gecko/20120410Firefox/3.6.28']defprocess_request(self,request,spider):importrandomrequest.headers['User-Agent']=random.choice(self.HEADERS)returnNone关于换IP看这里
讯代理动态转发#讯代理动态转发源码importrequestsimporthashlibimporttimeclassIP(object):def__init__(self,orderno,secret):self.orderno=ordernoself.secret=secretdefHeaders(self):timestamp=str(int(time.time()))#计算时间戳planText='orderno='+self.orderno+','+'secret='+self.secret+','+'timestamp='+timestamp#‘订单号’‘接口’‘时间戳’拼接出字符串string=planText.encode()#需要MD5加密需要转码md5_string=hashlib.md5(string).hexdigest()#planText拼接出的字符串进行MD5()sign=md5_string.upper()#转成大写auth='sign='+sign+'&'+'orderno='+self.orderno+'&'+'timestamp='+timestamp#‘加密的字符串’‘订单号’‘时间戳’拼接字符串headers=auth#认证的头部returnheadersif__name__=='__main__':#注意不同的网站,修改不同的httpip=IP('订单号','secret')proxy={'http':'http://forward.xdaili.cn:80'}headers={'Proxy-Authorization':ip.Headers()}print(headers)r=requests.get(url="http://httpbin.org/ip",headers=headers,proxies=proxy).json()print(r)随机IP开启下载中间件#Enableordisabledownloadermiddlewares#Seehttps://docs.scrapy.org/en/latest/topics/downloader-middleware.htmlDOWNLOADER_MIDDLEWARES={'IpApp.middlewares.IpappDownloaderMiddleware':543,}Spider源码classIpspiderSpider(scrapy.Spider):name='ipSpider'allowed_domains=['httpbin.org']start_urls=['http://httpbin.org/ip']defparse(self,response):print(response.text)yieldRequest(url=self.start_urls[0],dont_filter=True)设置随机IP在middlewares.py里编辑DownloaderMiddleware()类fromIpApp.xundailiimportIPclassIpappDownloaderMiddleware(object):defprocess_request(self,request,spider):ip=IP('订单号','secret')headers=ip.Headers()proxy='http://forward.xdaili.cn:80'request.headers['Proxy-Authorization']=headersrequest.meta['proxy']=proxyreturnNone测试结果小错误提示当使用认证类代理是出现找不到Proxy-Authorization的头部信息原因:scrapy会自动去掉Proxy-Authorization解决:进入scrapy的源码路径:scrapy\core\downloader\handlers\http11.py注释掉:#ifisinstance(agent,self._TunnelingAgent):#headers.removeHeader(b'Proxy-Authorization')或者使用框架提供的下载中间件```关于下载中间件的了解
说明上一个案例,对自带的ImagePipeline写了一个图片下载案例,现在对最后的小结进行改进对图片进行进行自定义名称存储主要涉及ImagePipeline类的继承与方法的重写优化开始优化Wallpaperspider.py文件defparse(self,response):#循环li标签forurltaginresponse.xpath('//ul[@class="clearfix"]/li/a'):#获取图片标题titles=urltag.xpath('./img/@alt').get()#获取图片链接url=urltag.xpath('./img/@src').get()#-->没有http://的链接urls_pic=response.urljoin(url)#拼接URL#传给数据ItemyieldImagesappItem(titles=titles,image_urls=urls_pic)优化pipeline.py文件继承ImagePipeline类导入ImagesPipeline类fromscrapy.pipelines.imagesimportImagesPipeline继承ImagesPipeline类classPicImagesPipeline(ImagesPipeline):pass重写get_media_requests()方法此方法是构造请求的Ruquest对象#构造下载,首先调用的函数defget_media_requests(self,item,info):#导入Request模块fromscrapy.http.requestimportRequest#在item中取出url,再把item给meta参数进行传递#在后面方法中,可以从request对象的meta属性获得item的数据yieldRequest(url=item['image_urls'],meta={'item':item})重写file_path()方法此方法是返回存储的路径deffile_path(self,request,response=None,info=None):#从request对象的meta属性获取titletitle=request.meta['item']['titles']#构造存储路径path=title+'.jpg'returnpath修改settings.py文件因为使用了自定义的Pipeline,所以我们需要指定我们重写的Pipeline#Configureitempipelines#Seehttps://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES={'ImagesApp.pipelines.PicImagesPipeline':1,#继承的重写ImagesPipeline类}运行爬虫scrapycrawlWallPaperSpider
使用官方提供的PiplineScrapy框架为下载的item中包含的图片提供了一个可以重用的图片下载pipeline。这些pipeline有共同的方法和结构。一般会使用到有FilesPipeline、ImagesPipline。使用官方Pipline的好处避免重新下载最近已经下载的数据方便指定下载的路径方便的转换图片的格式方便生成略缩图方便检测图片的宽高,确保满足最小值异步下载,效率非常高ImagesPipline的使用准备使用ImagesPipline,需要提前下载好Pillow图片处理库当使用ImagesPipline下载图片的时候,按照以下步骤完成1.定义Item属性必须要定义两个个默认的item属性:image_urls:存储下载图片的链,需要传递一个列表。images:文件下载完成后,会把图片的相关信息存储到这个属性里,比如下载的路径、下载的URL、文件的校验码…classMaybachItem(scrapy.Item):image_urls=scrapy.Field()images=scrapy.Field()2.启用ImagesPipline管道在settings.py里开启#Configureitempipelines#Seehttps://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES={#'Maybach.pipelines.MaybachPipeline':300,#开启图片下载器'scrapy.pipelines.images.ImagesPipeline':1,}3.配置ImagesPipline下载路径在settings.py里添加上#ImagesPipline下载路径,可以使用OS模块来指定路径#没有这个路径,会自动创建IMAGES_STORE='路径'0x00创建爬虫工程scrapystartprojectImagesApp(创建Scrapy工程)cdImagesApp(进入工程目录)scrapygenspiderWallPaperSpiderpic.netbian.com(创建爬虫)0x01配置爬虫关闭机器人协议#Obeyrobots.txtrulesROBOTSTXT_OBEY=False设置请求头#Crawlresponsiblybyidentifyingyourself(andyourwebsite)ontheuser-agentUSER_AGENT='Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/76.0.3809.100Safari/537.36'开启ImagesPipline管道#Configureitempipelines#Seehttps://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES={#'ImagesApp.pipelines.ImagesappPipeline':300,(注释掉)'scrapy.pipelines.images.ImagesPipeline':1,}配置图片的下载路径importosIMAGES_STORE=os.path.join(os.path.dirname(os.path.dirname(__file__)),'img')设置Item属性在items.py里classImagesappItem(scrapy.Item):#definethefieldsforyouritemherelike:#name=scrapy.Field()image_urls=scrapy.Field()images=scrapy.Field()0x02编写爬虫程序通过对网页的分析,我们需要的链接在这些li标签下获取图片链接但这些url,没有协议头defparse(self,response):url=response.xpath('//ul[@class="clearfix"]/li/a/img/@src').getall()print(url)添加协议头response.urljoin(url)方法会自动把相应的协议头加上urls_pic=list(map(lambdaurl:response.urljoin(url),urls))把图片链接通过Item传给ImagesPipeline下载导入ImagesappItem,传入url列表,启动爬虫fromImagesApp.itemsimportImagesappItemdefparse(self,response):urls=response.xpath('//ul[@class="clearfix"]/li/a/img/@src').getall()urls_pic=list(map(lambdaurl:response.urljoin(url),urls))yieldImagesappItem(image_urls=urls_pic)#启动爬虫scrapycrawlWallPaperSpider0x03小结这个小案例是直接使用的官方的ImagePipeline下载,所以没有对图片进行重命名,或者分类等操作,需要实现这些操作,就需要继承ImagesPipeline类,然后重新里面的相关方法,可以查看改进版。
__file__函数返回当前文件的绝对路径>>>print(__file__)"D://a/b/c.py"os.path.dirname(path)函数返回文件路径>>>os.path.dirname(__file__)"D://a/b/">>>os.path.dirname(os.path.dirname(__file__))"D://a/"os.path.exists(path)函数如果路径path存在,返回True;如果路径path不存在,返回Falseos.path.isfile(path)函数判断path是文件,返回True;不是,返回Falseos.path.isdir(path)函数判断path是目录,返回True;不是,返回Falseos.path.getsize(path)函数返回文件大小,如果文件不存在就返回错误os.path.join(path,*paths)函数把几个路径合成一个新路径>>>path=os.path.join('D://a/b','img')"D://a/b/img"os.path.splitext(path)函数分割文件名,返回由文件名和扩展名组成的元组>>>os.path.splitext("/home/test.sh")('/home/test','.sh')