本人是一名java程序员。最近公司须要创建一个车辆的基础信息库。须要去网络上爬取相关的数据。以前都是使用java来编写爬虫。一直以来呢都想学习一下python的相关知识,拓宽本身的知识面。以前对python算是零基础,正好有一个项目需求,趁这个机会呢,学习一下python的相关知识。因此使用了python来编写这个爬虫。因此这篇文章属于我在使用python编写爬虫的一份学习笔记。记录一下在使用python时遇到的一些难题和疑惑内容可能会有错误,编写的代码上规范也不足。但愿之后能慢慢的长进。html
IDE:idea。因为是个java程序员,因此编译器也就没有下载PyCharm。据说很好用。可是人比较懒,仍是之后idea实在用不顺手再专门换吧java
python版本:2.7(为何不用python3?我也不知道python版本2,3之间具体的区别。可是想着java的版本更新到12了。你们用的最广泛的仍是java8,就选个老版本的下载了。不少疑惑留着之后慢慢解决吧,毕竟是个项目需求,先让项目跑起来再说hhh)python
前情提要完毕,接下来开始撸代码git
首先我爬的是汽车之家的信息。一共分三步程序员
import requests
from bs4 import BeautifulSoup
复制代码
主要使用了两个模块,使用requests能够模拟浏览器的请求,相似于java里的httpclient。Beautiful Soup 是一个能够从 HTML 或 XML 文件中提取数据的 Python 库能够用来解析咱们爬取到的网页信息。 python里安装相关模块很是的简单。在控制台输入pip install ***相关模块就能够安装使用了。 在 pypi.org/project能够搜索你想要的安装的模块得到对应的命令github
下面是我爬取汽车之家网页信息的开始部分代码,也就是请求的部分。一共三个网址,分别第一个url是获取车辆品牌信息,这个网页有全部的车辆品牌信息,第二个typeUrl是每一个品牌具体的型号信息。第三个messageUrl是每款型号的具体配置信息。有了这三个网址,其实你们就能够用本身熟悉的语言去爬取咱们想要的全部的车辆信息了(其实没有全部的,好比车辆vin码信息。正是为了这个信息,我后面放弃了爬取汽车之家的信息,又去爬取了工信部的车辆信息。那个爬取的难度更加的大。)chrome
'''爬取汽车之家车辆信息'''
url = 'https://car.m.autohome.com.cn/' # 获取车辆品牌信息
typeUrl = 'https://m.autohome.com.cn/' # 车辆型号信息
messageUrl = 'https://car.m.autohome.com.cn/ashx/car/GetModelConfig2.ashx?ids=' #车辆具体信息
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36'
}
httpdatasf = codecs.open(unicode("http代理ip",'utf-8'),"r",encoding='utf-8') #设置文件对象
httpdatas = httpdatasf.readlines() #直接将文件中按行读到list里,效果与方法2同样
httpdatasf.close()
httpsdatasf = codecs.open(unicode("https代理ip",'utf-8'),"r",encoding='utf-8') #设置文件对象
httpsdatas = httpsdatasf.readlines() #直接将文件中按行读到list里,效果与方法2同样
httpsdatasf.close()
requests.adapters.DEFAULT_RETRIES = 8
s = requests.session()
s.keep_alive = False #设置不保持链接,不然会未关闭的链接太多报错
s.proxies = {"https": random.choice(httpsdatas) , "http": random.choice(httpdatas) }#代理ip 获取网址http://www.zdaye.com/FreeIPlist.html
res = requests.get(url, headers=headers)
soup = BeautifulSoup(res.text, 'html.parser')
复制代码
http代理和https代理是我在网上找到的一些免费的代理ip(以下图)。由于爬虫爬网站信息毕竟是不少网站都不喜欢的事情。为了防止IP被封,咱们须要设置一些代理IP去发送请求。经过request获取session,而后在proxies里设置好http和https的代理就行了。IP代理获取地址能够在www.zdaye.com/FreeIPlist.… 这个网站找到。每一个IP存活的时间有长有短。为了防止你在爬虫的时候时不时IP就不可用了,优先采用那些存活时间久一点的IP。对请求加入header,可让咱们的请求看起来更像是真实的网络请求。设置keep——alive=False这个比较重要,若是不设置的话,打开太多连接后就会报Max retries exceeded with url的错误。而后咱们使用BeautifulSoup就能够获取到请求所返回的网页对象了。json
下面这段代码就是正式的爬取汽车之家车辆具体信息的三部曲了。首先咱们将request返回信息用BeautifulSoup包装起来。BeautifulSoup的用法网上有不少例子,这里我不作具体一一表述。自己也就是一份学习笔记,也没有必要把用到的全部的东西一一清楚介绍。浏览器
咱们所要爬取的车辆品牌信息在id名为‘div_ListBrand’的标签中。其中find方法查找的是一个元素,find_all方法查找的是一个结果集。因此要for循环每个li标签就是每个品牌名称的一个id号了。获取到这个li标签须要获取li标签里的值。这里id存在了‘v’元素对应的值里因此去li['v']就获取了id。若是你要获取li的value对应的值就是li['value'],以此类推。安全
咱们获取了每一个品牌对应的id后,须要查找这个品牌下的车型url2(额,这个网址没定义到全局里,因为赶进度,因此这个代码里可能有不少不规范的地方,命名啊,之类的。见谅,之后有空再改吧hh)这个请求呢返回的不是一个网页。而是一串json字符串。因此咱们用了get请求,将response转出json进行处理。python获取json字符串里的值得方法跟以前获取网页标签元素的值相似。
以后咱们将爬取到的车辆型号信息写入文件中,经过open方法能够建立文件,w表示写入,具体还有追加,读等等操做能够百度或者谷歌。这里作点补充,open方法只能open英文名的文件。(不知道是否是啊,反正我打开中文名的文件是失败了的)因此以前我打开个人ip代理地址文件时,采用的是codecs模块的open方法。
codecs.open(unicode("https代理ip",'utf-8'),"r",encoding='utf-8')
复制代码
像这样加个encoding='utf-8'便可。python的编码问题还挺多的。不少时候咱们爬取到网页的请求得到的字符串是unicode编码的。好比下面代码获取的json字符串,咱们直接输出到文件中就是unicode编码。json格式的处理方式是
json.dumps(param,ensure_ascii=False)
复制代码
加入ensure_ascii=False,便可正常输出中文而不是Unicode编码了
接下来的操做跟以前的也同样,咱们将车辆型号id加到typeUrl后,获取车辆型号信息。最后呢因为每款型号又具体再有细分。原本我也是像请求获取具体车辆型号的网页信息而后解析的。当我解析以后发现,我须要的数据所在的div是空的。这是因为这些数据都是动态渲染上去的。在此,咱们有两种解决办法,一个是此次使用的办法,打开chrome控制台,打开network标签,找到对应获取车辆型号具体数据的请求。在这里我找到了获取后台数据的请求就是messageUrl了。而后一样采用get请求的方式获得json字符串。而后对字符串进行对应的处理
soup = BeautifulSoup(res.text, 'html.parser')
tags = soup.find('div',{'id':'div_ListBrand'})
File = open("vehicle.txt", "w")
ullist = tags.find_all('ul')
for link in ullist:
lilist = link.find_all('li')
for li in lilist:
url2 ='https://car.m.autohome.com.cn/ashx/GetSeriesByBrandId.ashx?b=' + li['v']
response = requests.request("GET", url2, headers=headers)
data = response.json()
ary = data['result']
arry = ary['sellSeries']
for sell in arry:
File.write(str(sell['Id']) +' '+str(sell['name']) +'\n')
SeriesItems = sell['SeriesItems']
for SeriesItem in SeriesItems:
File.write(str(SeriesItem['id'])+' '+str(SeriesItem['name']) +'\n')
typeRes = requests.get(typeUrl+str(SeriesItem['id']), headers=headers)
typeSoup = BeautifulSoup(typeRes.text, 'html.parser')
typeTags = typeSoup.find('div',{'class':'summary-cartype'})
typeDivs = typeTags.find_all('div',{'class':'fn-hide'})
for typeDiv in typeDivs:
typeUls = typeDiv.find_all('ul')
for typeUl in typeUls:
typeLis = typeUl.find_all('li')
for typeLi in typeLis:
print messageUrl+str(typeLi['data-modelid'])
print typeLi.find('a',{'class':'caption'}).get_text()
File.write(typeLi.find('a',{'class':'caption'}).get_text()+'\n')
messageResponse = requests.request("GET", messageUrl+str(typeLi['data-modelid']), headers=headers)
messageData = messageResponse.json()
baseData = messageData['data']
baseJson = json.loads(baseData)
baikeconfigpar = baseJson['baikeconfigpar']
config = baseJson['config']
configbag = baseJson['configbag']
param = baseJson['param']
search = baseJson['search']
File.write(json.dumps(baikeconfigpar,ensure_ascii=False)+'\n')
File.write(json.dumps(config,ensure_ascii=False)+'\n')
File.write(json.dumps(param,ensure_ascii=False)+'\n')
File.write(json.dumps(configbag,ensure_ascii=False)+'\n')
File.write(json.dumps(search,ensure_ascii=False)+'\n')
File.close()
复制代码
最后咱们获得了车辆信息的具体信息,主要的参数放在了paramItems里。这里有些比较操蛋的是,这个json字符串里有些数据竟然是直接带js样式的好比这个 "value": "<span class='hs_kw0_configpl'></span>A3 2019款 Spo**rtback 35 TFSI 进取型 <span class='hs_kw1_configpl'></span>
后来因为汽车之家没有我想要的车辆vin码信息。我转而爬取了工信部的车辆信息。因此这方面对json数据的处理我也没有花精力去作。若是想要获得干净的数据。咱们还能够采起另外一种方法,直接获得网页动态渲染后的数据。这也是我在爬取工信部车辆数据所采用的方法。就是利用了selenium模块来模拟真实的浏览器请求。同时工信部获取车辆具体数据的接口还须要过一个滑动验证码的验证,一样能够利用selenium模块进行破解。关于这一部分的记录,等我有空了下回再写吧,由于还有一些问题没有处理完,一个就是python的多线程追加写入文件,如何保证写入的数据的线程安全。不过相关代码已上传到github上:github.com/chenyuhua32…
最后,学习一门新的语言仍是让我很是的有探索的快乐。但愿不断的记录下我学习中遇到的坑,让本身不断地更好的成长吧。!