
今天的scrapy项目难度升级一下,不仅要用到pipeline导出数据到mysql,还要通过middleware实现随机User-Agent。
爬取目标网站为我爱我家
terminal 中startproject以及genspider这里不赘述,有问题可以评论在下面。
首先在item中声明爬取的item,这里我们抓取5个目标
- 标题
- 链接
- 位置
- 价格
- 大小
import scrapy
class WoaiwojiaItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
url = scrapy.Field()
title = scrapy.Field()
info = scrapy.Field()
location = scrapy.Field()
price = scrapy.Field()
之后,就要进入到spider文件中写代码了。不得不说,这个网站用xpath解析真的非常痛苦,还是pyquery来的方便又简单。不过因为scrapy只支持xpath css和re,所以头发掉光也没辙。
【注意】import在items文件中的item类
【关键】在for循环便利li节点中的xpath解析式,一定要记得有' . ' (括号中的点),不然就会回到顶层 进行遍历。在这里卡了很久。。
解析完成,还要生成下一页的request,直接通过xpath找到下一页的相对url,并与base url拼接即可。这里注意dont filter = True,不然会被scrapy自动去重
import scrapy
from woaiwojia.items import WoaiwojiaItem
class WiwjSpider(scrapy.Spider):
name = 'wiwj'
allowed_domains = ['https://bj.5i5j.com/zufang']
start_urls = ['https://bj.5i5j.com/zufang/haidianqu/']
base_url = 'https://bj.5i5j.com'
def parse(self, response):
lis = response.xpath('//ul[@]//li')
#print(divs)
#print(len(lis))
item = WoaiwojiaItem()
for li in lis:
item['title'] = li.xpath('.//div[@]//h3//a/text()').extract_first()
item['url'] = li.xpath('.//div[@]//a/@href').extract_first()
#loc_pattern = re.compile('[sS](.*?)[sS]')
#item['location'] = loc_pattern.search(str(li)
#item['location'] = li.xpath('//div[@]//i[@/text()]').extract()
#item['location'] = li.re_first('s+"(.*?)"')
#正则提取出多个值,可以用用【index】定位
# MySql插入值报错,因为没有在info和location后面加【index】,而mysql不能插入列表!
item['info'] = li.re('(.*?)
')[1].split('·')[1]
item['location'] = li.re('s+(.*?)s+s+(.*?)s+<')[0]
item['price'] = li.xpath('.//div[@]//p[@]//text()').extract_first()
#item['info'] = li.xpath('//i[@/text()]').extract()
yield item
next = response.xpath('//div[@]//a').re('下一页')[0]
next_url = self.base_url + next
yield scrapy.Request(url=next_url,callback=self.parse,dont_filter=True)
到这里,可以尝试运行一下。
结果是什么呢?直接404报错。因为还有几个设置没有搞定 。
进入settings,添加ua以及关闭robots协议。
# Crawl responsibly by identifying yourself (and your website) on the user-agent USER_AGENT = 'User-Agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0' # Obey robots.txt rules ROBOTSTXT_OBEY = False
再次运行。
可以返回第一页结果,然而到了第二页,又是404。为什么会这样呢?
因为生成下一页的request没有调用settings中的ua,所以自然就跪了。解决方法也简单,就要用到我们的middleware了。这个middleware在spider和downloader之间,传递request要经过它,返回response也经过它,所以在request被downloader处理前,给他添油加醋一下,就可以了。
【注意】middleware的process_request是必须有的,而且不能改名。
import random
class RandomUAMiddleware:
def __init__(self):
self.ua_list = [
'User-Agent=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
'User-Agent=Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)',
'User-Agent=Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
'User-Agent=Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)',
'User-Agent=Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)',
'User-Agent=Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)',
'User-Agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)',
'User-Agent=Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6',
'User-Agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1',
'User-Agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0',
]
def process_request(self,request,spider):
request.headers['User-Agent'] = random.choice(self.ua_list)
之后,回到settings中,打开middleware
DOWNLOADER_MIDDLEWARES = {
#'woaiwojia.middlewares.WoaiwojiaDownloaderMiddleware': 543,
'woaiwojia.middlewares.RandomUAMiddleware': 543,
}
完成后,运行一下。完美!需要的数据都咔咔咔的出现了。可是,要对这些数据进行永久保存怎么整呢?这就要用到pipeline。它不仅可以进一步处理数据,还能保存数据到数据库。这里演示将数据导入mysql中。首先建立database以及table,这里不赘述,有问题可以评价下方。
在pipeline中,编辑如下代码。
【注意】一定要commit(),不然数据导不进去
from itemadapter import ItemAdapter
import pymysql
class WoaiwojiaPipeline:
def __init__(self,host,port,user,pwd,db):
self.host = host
self.port = port
self.user = user
self.pwd = pwd
self.db = db
@classmethod
def from_crawler(cls,crawler):
return cls(
host=crawler.settings.get('HOST'),
port=crawler.settings.get('PORT'),
user=crawler.settings.get('USER'),
pwd=crawler.settings.get('PWD'),
db=crawler.settings.get('DB'),
)
def open_spider(self,spider):
self.conn = pymysql.connect(host=self.host,port=self.port,user=self.user,password=self.pwd,database=self.db)
self.cursor = self.conn.cursor()
def process_item(self, item, spider):
title = item['title']
url = item['url']
info = item['info']
location = item['location']
price = item['price']
sql = 'insert into wiwj(title,url,location,info,price) values(%s,%s,%s,%s,%s)'
values = (title,url,location,info,price)
self.cursor.execute(sql,values)
self.conn.commit()
def close_spider(self,spider):
self.cursor.close()
self.conn.close()
在settings中设置mysql相关设置并打开pipeline
ITEM_PIPELINES = {
'woaiwojia.pipelines.WoaiwojiaPipeline': 300,
}
HOST = 'localhost'
PORT = 3306
USER = 'root'
PWD = '123123123'
DB = 'wiwj'
ok 一切就绪。再次运行,数据就会全部导入数据库中啦。
成果展示
肯定有人好奇,我这爬取的只有北京海淀区啊,哪里是全站。
这个就交给大家自行学习了,只需简单改动即可实现。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)