>  기사  >  백엔드 개발  >  Python으로 크롤러를 작성하는 경험을 기록합니다.

Python으로 크롤러를 작성하는 경험을 기록합니다.

高洛峰
高洛峰원래의
2016-11-21 17:05:001427검색

요즘에는 Node.js나 Go, 심지어 PHP까지 웹 크롤러를 작성하는 방법이 많습니다. 제가 Python을 선택한 이유는 튜토리얼도 많고, 배우기만 하면 체계적으로 배울 수 있기 때문입니다. HTML 선택기를 사용하여 크롤링하는 방법을 알고 있습니다. 페이지만으로는 충분하지 않습니다. 또한 크롤링 과정에서 발생할 수 있는 몇 가지 일반적인 함정과 브라우저 헤더 수정에 대한 팁과 같은 몇 가지 주의 사항도 알고 싶습니다.

코드 주석이 아주 자세하게 나와있습니다. 사실 소스코드를 직접 읽어보기만 하면 됩니다.

이 크롤러의 목적은 매우 간단합니다. 부동산 웹사이트의 이름 + 가격 + 사진 다운로드 1장을 크롤링하여 나중에 주택 가격 추세를 분석하는 것입니다. 상대방 서버의 부담이 너무 커져서 3페이지만 크롤링하기로 결정했습니다.

주의해야 할 몇 가지 지식 사항에 대해 이야기하겠습니다.

#보내는 헤더 수정을 기억하세요
기본적으로 Python 정보가 포함된 헤더가 전송된다고 들었습니다. , 정말 이상한 일입니다. 다른 웹사이트에서는 크롤러 로봇으로 감지되기 ​​쉽기 때문에 IP가 차단될 수 있으므로 크롤러 프로그램을 좀 더 인간처럼 만드는 것이 가장 좋지만 이 코드는 일반 기능만 수행할 수 있습니다. 크롤러를 막고 싶은 웹사이트가 있다면 역시 거짓말을 하는 것입니다. 그러나 위의 코드는

headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit 537.36 (KHTML, like Gecko) Chrome",
                "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"},

#html 선택기, beautifulsoup 대신 pyquery를 사용합니다
많은 책에서 beautifulsoup를 추천합니다. , 하지만 jquery에 익숙한 사람으로서 beautifulsoup의 구문은 정말 말이 좀 많고, first-child와 같은 고급 및 복잡한 CSS 선택기 모드를 지원하지 않거나 지원할 수도 있는 것 같습니다. , 그러나 찾을 수 없었고 설명서를 주의 깊게 읽지도 않았습니다.

그러다가 온라인에서 정보를 찾아보니 많은 분들이 pyquery 라이브러리를 추천해 주셨고, 직접 써보니 정말 편하다고 해서 과감하게 채택하게 되었습니다.

#크롤러 아이디어
아이디어는 실제로 매우 간단합니다.
1. 특정 부동산의 목록 페이지를 찾아 두 번째 및 세 번째 페이지의 URL 구조를 분석합니다.
2. 각 목록 페이지의 모든 목록 항목 정보의 URL은 Python의 set() 컬렉션에 저장됩니다. set을 사용하는 이유는 중복된 URL 정보를 제거하기 위한 것입니다.
3. 집의 URL을 얻어 세부정보 페이지에 진입한 후, 사진, 텍스트 등 귀중한 현장 정보를 크롤링합니다.
4. 현재는 데이터만 인쇄하고 로컬 json 또는 CSV 형식으로 저장하지 않습니다.

전체 코드는 다음과 같습니다.

#获取页面对象
from urllib.request import urlopen
from urllib.request import urlretrieve
from pyquery import PyQuery as pq
#修改请求头模块,模拟真人访问
import requests
import time
#引入系统对象
import os

#你自己的配置文件,请将config-sample.py重命名为config.py,然后填写对应的值即可
import config

#定义链接集合,以免链接重复
pages = set()
session = requests.Session()
baseUrl = 'http://pic1.ajkimg.com'
downLoadDir = 'images'

#获取所有列表页连接
def getAllPages():
    pageList = []
    i = 1
    while(i < 2):
        newLink = &#39;http://sh.fang.anjuke.com/loupan/all/p&#39; + str(i) + &#39;/&#39;
        pageList.append(newLink)
        i = i + 1
    return pageList

def getAbsoluteURL(baseUrl, source):
    if source.startswith("http://www."):
        url = "http://"+source[11:] 
    elif source.startswith("http://"):
        url = source
    elif source.startswith("www."):
        url = "http://"+source[4:] 
    else:
        url = baseUrl+"/"+source 
    if baseUrl not in url:
        return None 
    return url

#这个函数内部的路径按照自己的真实情况来写,方便之后的数据导入
def getDownloadPath(baseUrl, absoluteUrl, downloadDirectory): 
    path = absoluteUrl.replace("www.", "")
    path = path.replace(baseUrl, "")
    path = downloadDirectory+path
    directory = os.path.dirname(path)
    if not os.path.exists(directory): 
        os.makedirs(directory)
    return path

#获取当前页面的所有连接
def getItemLinks(url):
    global pages;
    #先判断是否能获取页面
    try:
        req = session.get(url, headers = config.value[&#39;headers&#39;])
    #这个判断只能判定是不是404或者500的错误,如果DNS没法解析,是无法判定的
    except IOError as e:
        print(&#39;can not reach the page. &#39;)
        print(e)
    
    else: 
        h = pq(req.text)
        #获取第一页的所有房子模块
        houseItems = h(&#39;.item-mod&#39;)
        #从模块中提取我们需要的信息,比如详情页的URL,价格,略缩图等
        #我倾向只获取详情页的URL,然后在详情页中获取更多的信息
        for houseItem in houseItems.items():
            houseUrl = houseItem.find(&#39;.items-name&#39;).attr(&#39;href&#39;)
            #print(houseUrl)
            pages.add(houseUrl)
        
#获取详情页的各种字段,这里可以让用户自己编辑
def getItemDetails(url):
    #先判断是否能获取页面
    try:
        req = session.get(url, headers = config.value[&#39;headers&#39;])
    #这个判断只能判定是不是404或者500的错误,如果DNS没法解析,是无法判定的
    except IOError as e:
        print(&#39;can not reach the page. &#39;)
        print(e)
    else:
        time.sleep(1)
        h = pq(req.text)

        #get title
        housePrice = h(&#39;h1&#39;).text() if h(&#39;h1&#39;) != None else &#39;none&#39;

        #get price
        housePrice = h(&#39;.sp-price&#39;).text() if h(&#39;.sp-price&#39;) != None else &#39;none&#39;

        #get image url
        houseImage = h(&#39;.con a:first-child img&#39;).attr(&#39;src&#39;)
        houseImageUrl = getAbsoluteURL(baseUrl, houseImage)
        if houseImageUrl != None:
            urlretrieve(houseImageUrl, getDownloadPath(baseUrl, houseImageUrl, downLoadDir))     
        # if bsObj.find(&#39;em&#39;,{&#39;class&#39;,&#39;sp-price&#39;}) == None:
        #     housePrice = &#39;None&#39;
        # else:
        #     housePrice = bsObj.find(&#39;em&#39;,{&#39;class&#39;,&#39;sp-price&#39;}).text;
        # if bsObj.select(&#39;.con a:first-child .item img&#39;)== None:
        #     houseThumbnail = &#39;None&#39;
        # else:
        #     houseThumbnail = bsObj.select(&#39;.con a:first-child .item img&#39;);

        


#start to run the code
allPages = getAllPages()

for i in allPages:
    getItemLinks(i)
#此时pages 应该充满了很多url的内容
for i in pages:
    getItemDetails(i)
#print(pages)


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.