之前的文章都是与职位、热门文章有关的,今天一起来看一下知乎上与python相关的精华回答(主要是requests,scrapy处理的思路,编码问题)
主要获取以上信息,接着我们来看一下这些字段所在的位置
通过观察和分析以上字段在源码中都能找到,所以就不用像前几篇文章那样,构造参数,解析获取返回的json数据,我们可以通过lxml.etree.HTML()或者Beautifulsoup去解析(这里在通过etree解析时遇到了一些问题,在后边会进行解释)
既然不需要通过构造参数去获取数据了,所以相对来说就简单一些了,接下来我们来看一下另一个很重要的问题——分页问题
从上面两张图片我们可以看出换页之后参数page发生了改变,很显然page控制的是页码,明白了这一点就可以去构造URL了
urls = ['https://www.zhihu.com/topic/19552832/top-answers?page={}'.format(one) for one in range(1,51)]
解决了分页问题,就没什么难点了,接下来说一下遇到的问题和解决方法
# -*- coding:utf-8 -*- import requests from bs4 import BeautifulSoup from store_csv import CSV from store_mysql import Mysql class zhiHu(object): baseurl = 'https://www.zhihu.com' headers = { "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" } cookies = { 'd_c0': '"AHACIj6lFguPTkEZTVmz8MPJ8UkcuI03hag=|1483278273"', '_zap': '108369f2-93e6-407e-8928-b57f44168838', 'q_c1': '0d3d690c67bc4b12a163beb462e17d67|1492571575000|1483278273000', 'cap_id': '"NmFlNDgyZmMxNWQ0NGFiYmFhZThmMGM2MDVkZDM1MWM=|1493684435|1958b2bb9fb6f09116056cc4bc5af76e00dbaff7"', 'l_cap_id': '"ZjViYmQ0MzBkNTFjNGJjOWE5YTExZWRjMjlkNjM2YjQ=|1493684435|1204e5c054805d8bebf3b49a8a2fc09e2f1bd870"', 'auth_type': '"c2luYQ==|1493684515|245a0f575f151c486829c687ba3d3c90fc5fa558"', 'token': '"Mi4wMGljWjNYRkVBNzIyRGJjZDZkMjMyZmMwM2JtMWs=|1493684515|a76491c048b7e825a77983ef0a272bdc9e721853"', 'client_i': '"NTA3MzY2MzQwNA==|1493684515|9a08a2c9a6c02e86da4810cb5bc4437f6d7b1028"', 'aliyungf_tc': 'AQAAAFOsE04F5QQAHVcc2i2qHTGdX1x0', 'acw_tc': 'AQAAAAnnBnQS0AcAHVcc2omDblHld+wt', '_xsrf': '398e0b041f39355dadfc06b76ba18cdb', 's-q': 'python', 's-i': '1', 'sid': 'ob2ttqkg', 's-t': 'autocomplete', 'z_c0': 'Mi4wQUFBQ3hmbTFzUXNBY0FJaVBxVVdDeGNBQUFCaEFsVk5OVjR2V1FETW9QS19PRlExWGVjUHNOcFVoTG5mYWg1LUtR|1493701061|4258e8f2ddc800c42c8b7d94385f578ca97f34d5', '__utma': '51854390.213172690.1484833633.1493684449.1493701029.4', '__utmb': '51854390.0.10.1493701029', '__utmc': '51854390', '__utmz': '51854390.1493701029.4.4.utmcsr=baidu|utmccn=(organic)|utmcmd=organic', '__utmv': '51854390.100--|2=registration_date=20170502=1^3=entry_date=20170101=1' } def getUrl(self): urls = ['https://www.zhihu.com/topic/19552832/top-answers?page={}'.format(one) for one in range(1,51)] for url in urls: self.getData(url) def getData(self,url): data = requests.get(url, headers=self.headers, cookies=self.cookies).content.encode('utf-8') soup = BeautifulSoup(data, 'lxml') infos = soup.find_all('div', {'class': 'feed-item feed-item-hook folding'}) item = {} for info in infos: item[1] = info.find('a',{'class':'question_link'}).get_text().strip() item[1] = item[1].replace("'","=") item[2] = self.baseurl+info.find('a',{'class':'question_link'}).get('href') try: item[3] = info.find('a',{'class':'author-link'}).get_text() except: item[3] = u'匿名用户' try: item[4] = self.baseurl+info.find('a',{'class':'author-link'}).get('href') except: item[4] = u'' item[5] = info.find('a',{'class':'zm-item-vote-count js-expand js-vote-count'}).get_text() try: item[6] = self.baseurl+info.find('a',{'class':'toggle-expand'}).get('href') except: item[6] = u'' self.store(item) def store(self,item={}): #row = [item[i] for i in range(1,7)] #wirte.writeRow(row) mysql.insert(item) if __name__ == "__main__": #firstRow = ['问题', '问题URL', '回答者', '回答者URL', '获赞', '详细信息URL'] #wirte = CSV('zhihu.csv',firstRow) row = ['question','qurl','autuor','aurl','zan','detail'] mysql = Mysql('zhihu',row,7) mysql.create_table() zhihu = zhiHu() zhihu.getUrl()
这里说明一点,from store_csv import CSV,from store_mysql import Mysql这两个是自己写的两个类,实现方法可以参考python简单操作csv文件小例和老哥Mr_Cxy的python对Mysql数据库的操作小例这两篇文章,这里可以不添加cookie信息
selector = etree.HTML(html.content.decode('utf-8'))
通过对html.content进行解码,输出结果正常。
yield scrapy.Request(url,callback=self.parse)
代码中提到的URL指的是下一页的URL,通过获取下一页信息调用parse函数抓取信息
2.之前通过观察URL,我们发现只有page之后的数字发生了变化,所以我们可以使用爬取规则CrawlSpider去获取不同页面的信息(给一个之前抓取智联招聘职位详情页面的规则作为参考)
# -*- coding: utf-8 -*- from scrapy.spider import CrawlSpider,Rule from scrapy.linkextractors import LinkExtractor from ..items import ZlzpItem class ZLZP_Spider(CrawlSpider): name = 'ZLZP' start_urls = [ 'http://jobs.zhaopin.com/' ] rules = [ Rule(LinkExtractor(allow=('http://jobs.zhaopin.com/[a-zA-Z0-9]*/.htm',)), follow=True, callback='parse_item')] def parse_item(self, response):
这里使用了parse_item进行页面数据的提取(编写爬虫规则时,避免使用 parse 作为回调函数。 由于 CrawlSpider 使用 parse方法来实现其逻辑,如果覆盖了 parse方法,crawl spider 将会运行失败。)
关于CrawlSpider 的详细使用方法可以参考官方文档或者参考相关的代码和文章
通过对比动态网页(ajax)和静态网页,在思想上差别不是很大(参数+分页),在解析方式动态的一般都是通过解析json来获取数据,静态则通过Beautifulsoup、xpath、正则去获取数据。
爬爬爬,下一个网站走起!